Merge "Zygote: preload Vulkan driver if hwui renders with Vulkan"
diff --git a/Android.bp b/Android.bp
index e19fe640..0780f88 100644
--- a/Android.bp
+++ b/Android.bp
@@ -433,7 +433,7 @@
"apex_aidl_interface-java",
"suspend_control_aidl_interface-java",
"framework-protos",
- "game-driver-protos",
+ "updatable-driver-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.0-java",
"android.hardware.cas-V1.1-java",
@@ -467,6 +467,7 @@
"com.android.sysprop.apex",
"com.android.sysprop.init",
+ "com.android.sysprop.localization",
"PlatformProperties",
],
sdk_version: "core_platform",
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 65c28fb..9ac8c87 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -20,6 +20,7 @@
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib-platform",
],
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 57595a2..51f6a76 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,6 +16,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.autofill">
+ <uses-sdk android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 23f025b..5a04ba3 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -27,7 +27,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.utils.blob.DummyBlobData;
+import com.android.utils.blob.FakeBlobData;
import org.junit.After;
import org.junit.Before;
@@ -96,7 +96,7 @@
mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
try {
final List<Long> durations = new ArrayList<>();
- final DummyBlobData blobData = prepareDataBlob(fileSizeInMb);
+ final FakeBlobData blobData = prepareDataBlob(fileSizeInMb);
final TraceMarkParser parser = new TraceMarkParser(
line -> line.name.startsWith(ATRACE_COMPUTE_DIGEST_PREFIX));
while (mState.keepRunning(durations)) {
@@ -120,15 +120,15 @@
});
}
- private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
- final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
+ final FakeBlobData blobData = new FakeBlobData.Builder(mContext)
.setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
.build();
blobData.prepare();
return blobData;
}
- private void commitBlob(DummyBlobData blobData) throws Exception {
+ private void commitBlob(FakeBlobData blobData) throws Exception {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session);
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index 03ab5b6..92dbc26 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -17,11 +17,14 @@
"apct-perftests-overlay-apps",
"apct-perftests-resources-manager-apps",
"apct-perftests-utils",
+ "collector-device-lib",
"guava",
],
libs: ["android.test.base"],
+ data: [":perfetto_artifacts"],
+
platform_apis: true,
jni_libs: ["libperftestscore_jni"],
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 1b28913..4f8ee29 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -16,13 +16,40 @@
<configuration description="Runs CorePerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CorePerfTests.apk" />
</target_preparer>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto files in external storage-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
+
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
</configuration>
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index 9e95a10..9fa99853 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -19,6 +19,7 @@
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib",
"platform-test-annotations",
],
test_suites: ["device-tests"],
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 12ec9eb4..7851087 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -803,8 +803,8 @@
* <b>only</b> be used for situations where it is actually required that the alarm go off while
* in idle -- a reasonable example would be for a calendar notification that should make a
* sound so the user is aware of it. When the alarm is dispatched, the app will also be
- * added to the system's temporary whitelist for approximately 10 seconds to allow that
- * application to acquire further wake locks in which to complete its work.</p>
+ * added to the system's temporary power exemption list for approximately 10 seconds to allow
+ * that application to acquire further wake locks in which to complete its work.</p>
*
* <p>These alarms can significantly impact the power use
* of the device when idle (and thus cause significant battery blame to the app scheduling
@@ -855,8 +855,8 @@
* be used for situations where it is actually required that the alarm go off while in
* idle -- a reasonable example would be for a calendar notification that should make a
* sound so the user is aware of it. When the alarm is dispatched, the app will also be
- * added to the system's temporary whitelist for approximately 10 seconds to allow that
- * application to acquire further wake locks in which to complete its work.</p>
+ * added to the system's temporary power exemption list for approximately 10 seconds to allow
+ * that application to acquire further wake locks in which to complete its work.</p>
*
* <p>These alarms can significantly impact the power use
* of the device when idle (and thus cause significant battery blame to the app scheduling
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index 6d23635..876d73a 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -67,8 +67,8 @@
* Class to keep track of the information related to "force app standby", which includes:
* - OP_RUN_ANY_IN_BACKGROUND for each package
* - UID foreground/active state
- * - User+system power save whitelist
- * - Temporary power save whitelist
+ * - User+system power save exemption list
+ * - Temporary power save exemption list
* - Global "force all apps standby" mode enforced by battery saver.
*
* Test: atest com.android.server.AppStateTrackerTest
@@ -110,25 +110,25 @@
final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
/**
- * System except-idle + user whitelist in the device idle controller.
+ * System except-idle + user exemption list in the device idle controller.
*/
@GuardedBy("mLock")
- private int[] mPowerWhitelistedAllAppIds = new int[0];
+ private int[] mPowerExemptAllAppIds = new int[0];
/**
- * User whitelisted apps in the device idle controller.
+ * User exempted apps in the device idle controller.
*/
@GuardedBy("mLock")
- private int[] mPowerWhitelistedUserAppIds = new int[0];
+ private int[] mPowerExemptUserAppIds = new int[0];
@GuardedBy("mLock")
- private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
+ private int[] mTempExemptAppIds = mPowerExemptAllAppIds;
/**
* Per-user packages that are in the EXEMPT bucket.
*/
@GuardedBy("mLock")
- private final SparseSetArray<String> mExemptedPackages = new SparseSetArray<>();
+ private final SparseSetArray<String> mExemptBucketPackages = new SparseSetArray<>();
@GuardedBy("mLock")
final ArraySet<Listener> mListeners = new ArraySet<>();
@@ -177,10 +177,10 @@
int UID_FG_STATE_CHANGED = 0;
int UID_ACTIVE_STATE_CHANGED = 1;
int RUN_ANY_CHANGED = 2;
- int ALL_UNWHITELISTED = 3;
- int ALL_WHITELIST_CHANGED = 4;
- int TEMP_WHITELIST_CHANGED = 5;
- int EXEMPT_CHANGED = 6;
+ int ALL_UNEXEMPTED = 3;
+ int ALL_EXEMPTION_LIST_CHANGED = 4;
+ int TEMP_EXEMPTION_LIST_CHANGED = 5;
+ int EXEMPT_BUCKET_CHANGED = 6;
int FORCE_ALL_CHANGED = 7;
int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
@@ -192,10 +192,10 @@
"UID_FG_STATE_CHANGED",
"UID_ACTIVE_STATE_CHANGED",
"RUN_ANY_CHANGED",
- "ALL_UNWHITELISTED",
- "ALL_WHITELIST_CHANGED",
- "TEMP_WHITELIST_CHANGED",
- "EXEMPT_CHANGED",
+ "ALL_UNEXEMPTED",
+ "ALL_EXEMPTION_LIST_CHANGED",
+ "TEMP_EXEMPTION_LIST_CHANGED",
+ "EXEMPT_BUCKET_CHANGED",
"FORCE_ALL_CHANGED",
"FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
@@ -308,38 +308,39 @@
}
/**
- * This is called when an app-id(s) is removed from the power save whitelist.
+ * This is called when an app-id(s) is removed from the power save allow-list.
*/
- private void onPowerSaveUnwhitelisted(AppStateTrackerImpl sender) {
+ private void onPowerSaveUnexempted(AppStateTrackerImpl sender) {
updateAllJobs();
unblockAllUnrestrictedAlarms();
}
/**
- * This is called when the power save whitelist changes, excluding the
- * {@link #onPowerSaveUnwhitelisted} case.
+ * This is called when the power save exemption list changes, excluding the
+ * {@link #onPowerSaveUnexempted} case.
*/
- private void onPowerSaveWhitelistedChanged(AppStateTrackerImpl sender) {
+ private void onPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
updateAllJobs();
}
/**
- * This is called when the temp whitelist changes.
+ * This is called when the temp exemption list changes.
*/
- private void onTempPowerSaveWhitelistChanged(AppStateTrackerImpl sender) {
+ private void onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
// TODO This case happens rather frequently; consider optimizing and update jobs
// only for affected app-ids.
updateAllJobs();
- // Note when an app is just put in the temp whitelist, we do *not* drain pending alarms.
+ // Note when an app is just put in the temp exemption list, we do *not* drain pending
+ // alarms.
}
/**
* This is called when the EXEMPT bucket is updated.
*/
- private void onExemptChanged(AppStateTrackerImpl sender) {
+ private void onExemptBucketChanged(AppStateTrackerImpl sender) {
// This doesn't happen very often, so just re-evaluate all jobs / alarms.
updateAllJobs();
unblockAllUnrestrictedAlarms();
@@ -709,8 +710,8 @@
&& !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
final String pkgName = intent.getData().getSchemeSpecificPart();
- if (mExemptedPackages.remove(userId, pkgName)) {
- mHandler.notifyExemptChanged();
+ if (mExemptBucketPackages.remove(userId, pkgName)) {
+ mHandler.notifyExemptBucketChanged();
}
}
}
@@ -727,12 +728,12 @@
synchronized (mLock) {
final boolean changed;
if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
- changed = mExemptedPackages.add(userId, packageName);
+ changed = mExemptBucketPackages.add(userId, packageName);
} else {
- changed = mExemptedPackages.remove(userId, packageName);
+ changed = mExemptBucketPackages.remove(userId, packageName);
}
if (changed) {
- mHandler.notifyExemptChanged();
+ mHandler.notifyExemptBucketChanged();
}
}
}
@@ -748,13 +749,13 @@
private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
private static final int MSG_UID_FG_STATE_CHANGED = 1;
private static final int MSG_RUN_ANY_CHANGED = 3;
- private static final int MSG_ALL_UNWHITELISTED = 4;
- private static final int MSG_ALL_WHITELIST_CHANGED = 5;
- private static final int MSG_TEMP_WHITELIST_CHANGED = 6;
+ private static final int MSG_ALL_UNEXEMPTED = 4;
+ private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
+ private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
private static final int MSG_FORCE_ALL_CHANGED = 7;
private static final int MSG_USER_REMOVED = 8;
private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
- private static final int MSG_EXEMPT_CHANGED = 10;
+ private static final int MSG_EXEMPT_BUCKET_CHANGED = 10;
private static final int MSG_ON_UID_STATE_CHANGED = 11;
private static final int MSG_ON_UID_ACTIVE = 12;
@@ -777,19 +778,19 @@
obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
}
- public void notifyAllUnwhitelisted() {
- removeMessages(MSG_ALL_UNWHITELISTED);
- obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
+ public void notifyAllUnexempted() {
+ removeMessages(MSG_ALL_UNEXEMPTED);
+ obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget();
}
- public void notifyAllWhitelistChanged() {
- removeMessages(MSG_ALL_WHITELIST_CHANGED);
- obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
+ public void notifyAllExemptionListChanged() {
+ removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED);
+ obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget();
}
- public void notifyTempWhitelistChanged() {
- removeMessages(MSG_TEMP_WHITELIST_CHANGED);
- obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
+ public void notifyTempExemptionListChanged() {
+ removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED);
+ obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget();
}
public void notifyForceAllAppsStandbyChanged() {
@@ -802,9 +803,9 @@
obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
}
- public void notifyExemptChanged() {
- removeMessages(MSG_EXEMPT_CHANGED);
- obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
+ public void notifyExemptBucketChanged() {
+ removeMessages(MSG_EXEMPT_BUCKET_CHANGED);
+ obtainMessage(MSG_EXEMPT_BUCKET_CHANGED).sendToTarget();
}
public void doUserRemoved(int userId) {
@@ -866,32 +867,32 @@
mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
return;
- case MSG_ALL_UNWHITELISTED:
+ case MSG_ALL_UNEXEMPTED:
for (Listener l : cloneListeners()) {
- l.onPowerSaveUnwhitelisted(sender);
+ l.onPowerSaveUnexempted(sender);
}
- mStatLogger.logDurationStat(Stats.ALL_UNWHITELISTED, start);
+ mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start);
return;
- case MSG_ALL_WHITELIST_CHANGED:
+ case MSG_ALL_EXEMPTION_LIST_CHANGED:
for (Listener l : cloneListeners()) {
- l.onPowerSaveWhitelistedChanged(sender);
+ l.onPowerSaveExemptionListChanged(sender);
}
- mStatLogger.logDurationStat(Stats.ALL_WHITELIST_CHANGED, start);
+ mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start);
return;
- case MSG_TEMP_WHITELIST_CHANGED:
+ case MSG_TEMP_EXEMPTION_LIST_CHANGED:
for (Listener l : cloneListeners()) {
- l.onTempPowerSaveWhitelistChanged(sender);
+ l.onTempPowerSaveExemptionListChanged(sender);
}
- mStatLogger.logDurationStat(Stats.TEMP_WHITELIST_CHANGED, start);
+ mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start);
return;
- case MSG_EXEMPT_CHANGED:
+ case MSG_EXEMPT_BUCKET_CHANGED:
for (Listener l : cloneListeners()) {
- l.onExemptChanged(sender);
+ l.onExemptBucketChanged(sender);
}
- mStatLogger.logDurationStat(Stats.EXEMPT_CHANGED, start);
+ mStatLogger.logDurationStat(Stats.EXEMPT_BUCKET_CHANGED, start);
return;
case MSG_FORCE_ALL_CHANGED:
@@ -1004,7 +1005,7 @@
}
cleanUpArrayForUser(mActiveUids, removedUserId);
cleanUpArrayForUser(mForegroundUids, removedUserId);
- mExemptedPackages.remove(removedUserId);
+ mExemptBucketPackages.remove(removedUserId);
}
}
@@ -1020,39 +1021,39 @@
}
/**
- * Called by device idle controller to update the power save whitelists.
+ * Called by device idle controller to update the power save exemption lists.
*/
- public void setPowerSaveWhitelistAppIds(
- int[] powerSaveWhitelistExceptIdleAppIdArray,
- int[] powerSaveWhitelistUserAppIdArray,
- int[] tempWhitelistAppIdArray) {
+ public void setPowerSaveExemptionListAppIds(
+ int[] powerSaveExemptionListExceptIdleAppIdArray,
+ int[] powerSaveExemptionListUserAppIdArray,
+ int[] tempExemptionListAppIdArray) {
synchronized (mLock) {
- final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
- final int[] previousTempWhitelist = mTempWhitelistedAppIds;
+ final int[] previousExemptionList = mPowerExemptAllAppIds;
+ final int[] previousTempExemptionList = mTempExemptAppIds;
- mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
- mTempWhitelistedAppIds = tempWhitelistAppIdArray;
- mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
+ mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray;
+ mTempExemptAppIds = tempExemptionListAppIdArray;
+ mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray;
- if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
- mHandler.notifyAllUnwhitelisted();
- } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
- mHandler.notifyAllWhitelistChanged();
+ if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) {
+ mHandler.notifyAllUnexempted();
+ } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) {
+ mHandler.notifyAllExemptionListChanged();
}
- if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
- mHandler.notifyTempWhitelistChanged();
+ if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) {
+ mHandler.notifyTempExemptionListChanged();
}
}
}
/**
- * @retunr true if a sorted app-id array {@code prevArray} has at least one element
+ * @return true if a sorted app-id array {@code prevArray} has at least one element
* that's not in a sorted app-id array {@code newArray}.
*/
@VisibleForTesting
- static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
+ static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) {
int i1 = 0;
int i2 = 0;
boolean prevFinished;
@@ -1100,7 +1101,7 @@
*/
public boolean areAlarmsRestricted(int uid, @NonNull String packageName,
boolean isExemptOnBatterySaver) {
- return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
+ return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ false,
isExemptOnBatterySaver);
}
@@ -1109,7 +1110,7 @@
*/
public boolean areJobsRestricted(int uid, @NonNull String packageName,
boolean hasForegroundExemption) {
- return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
+ return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ true,
hasForegroundExemption);
}
@@ -1127,17 +1128,16 @@
* @return whether force-app-standby is effective for a UID package-name.
*/
private boolean isRestricted(int uid, @NonNull String packageName,
- boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
+ boolean useTempExemptionListToo, boolean exemptOnBatterySaver) {
if (isUidActive(uid)) {
return false;
}
synchronized (mLock) {
- // Whitelisted?
final int appId = UserHandle.getAppId(uid);
- if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
+ if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
return false;
}
- if (useTempWhitelistToo && ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
+ if (useTempExemptionListToo && ArrayUtils.contains(mTempExemptAppIds, appId)) {
return false;
}
if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
@@ -1148,7 +1148,7 @@
}
final int userId = UserHandle.getUserId(uid);
if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
- && mExemptedPackages.contains(userId, packageName)) {
+ && mExemptBucketPackages.contains(userId, packageName)) {
return false;
}
return mForceAllAppsStandby;
@@ -1225,34 +1225,34 @@
}
/**
- * @return whether a UID is in the user / system defined power-save whitelist or not.
+ * @return whether a UID is in the user / system defined power-save exemption list or not.
*
* Note clients normally shouldn't need to access it. It's only for dumpsys.
*/
- public boolean isUidPowerSaveWhitelisted(int uid) {
+ public boolean isUidPowerSaveExempt(int uid) {
synchronized (mLock) {
- return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
+ return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid));
}
}
/**
* @param uid the uid to check for
- * @return whether a UID is in the user defined power-save whitelist or not.
+ * @return whether a UID is in the user defined power-save exemption list or not.
*/
- public boolean isUidPowerSaveUserWhitelisted(int uid) {
+ public boolean isUidPowerSaveUserExempt(int uid) {
synchronized (mLock) {
- return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
+ return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid));
}
}
/**
- * @return whether a UID is in the temp power-save whitelist or not.
+ * @return whether a UID is in the temp power-save exemption list or not.
*
* Note clients normally shouldn't need to access it. It's only for dumpsys.
*/
- public boolean isUidTempPowerSaveWhitelisted(int uid) {
+ public boolean isUidTempPowerSaveExempt(int uid) {
synchronized (mLock) {
- return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
+ return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid));
}
}
@@ -1290,25 +1290,25 @@
pw.print("Foreground uids: ");
dumpUids(pw, mForegroundUids);
- pw.print("Except-idle + user whitelist appids: ");
- pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
+ pw.print("Except-idle + user exemption list appids: ");
+ pw.println(Arrays.toString(mPowerExemptAllAppIds));
- pw.print("User whitelist appids: ");
- pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
+ pw.print("User exemption list appids: ");
+ pw.println(Arrays.toString(mPowerExemptUserAppIds));
- pw.print("Temp whitelist appids: ");
- pw.println(Arrays.toString(mTempWhitelistedAppIds));
+ pw.print("Temp exemption list appids: ");
+ pw.println(Arrays.toString(mTempExemptAppIds));
- pw.println("Exempted packages:");
+ pw.println("Exempted bucket packages:");
pw.increaseIndent();
- for (int i = 0; i < mExemptedPackages.size(); i++) {
+ for (int i = 0; i < mExemptBucketPackages.size(); i++) {
pw.print("User ");
- pw.print(mExemptedPackages.keyAt(i));
+ pw.print(mExemptBucketPackages.keyAt(i));
pw.println();
pw.increaseIndent();
- for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
- pw.print(mExemptedPackages.valueAt(i, j));
+ for (int j = 0; j < mExemptBucketPackages.sizeAt(i); j++) {
+ pw.print(mExemptBucketPackages.valueAt(i, j));
pw.println();
}
pw.decreaseIndent();
@@ -1372,24 +1372,24 @@
}
}
- for (int appId : mPowerWhitelistedAllAppIds) {
- proto.write(AppStateTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
+ for (int appId : mPowerExemptAllAppIds) {
+ proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId);
}
- for (int appId : mPowerWhitelistedUserAppIds) {
- proto.write(AppStateTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+ for (int appId : mPowerExemptUserAppIds) {
+ proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId);
}
- for (int appId : mTempWhitelistedAppIds) {
- proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
+ for (int appId : mTempExemptAppIds) {
+ proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId);
}
- for (int i = 0; i < mExemptedPackages.size(); i++) {
- for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
- final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_PACKAGES);
+ for (int i = 0; i < mExemptBucketPackages.size(); i++) {
+ for (int j = 0; j < mExemptBucketPackages.sizeAt(i); j++) {
+ final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES);
- proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
- proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
+ proto.write(ExemptedPackage.USER_ID, mExemptBucketPackages.keyAt(i));
+ proto.write(ExemptedPackage.PACKAGE_NAME, mExemptBucketPackages.valueAt(i, j));
proto.end(token2);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index b1bafee..6c3398f 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -3715,7 +3715,7 @@
}
private void passWhiteListsToForceAppStandbyTrackerLocked() {
- mAppStateTracker.setPowerSaveWhitelistAppIds(
+ mAppStateTracker.setPowerSaveExemptionListAppIds(
mPowerSaveWhitelistExceptIdleAppIdArray,
mPowerSaveWhitelistUserAppIdArray,
mTempWhitelistAppIdArray);
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 6529503..4194fd0 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2089,7 +2089,7 @@
} else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
|| UserHandle.isSameApp(callingUid, mSystemUiUid)
|| ((mAppStateTracker != null)
- && mAppStateTracker.isUidPowerSaveUserWhitelisted(callingUid)))) {
+ && mAppStateTracker.isUidPowerSaveUserExempt(callingUid)))) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 06c469a..3234b27 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -89,6 +89,7 @@
import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
+import com.android.server.SystemService.TargetUser;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.controllers.BackgroundJobsController;
@@ -975,24 +976,24 @@
}
@Override
- public void onStartUser(int userHandle) {
+ public void onUserStarting(@NonNull TargetUser user) {
synchronized (mLock) {
- mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
+ mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
}
// Let's kick any outstanding jobs for this user.
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
- public void onUnlockUser(int userHandle) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
// Let's kick any outstanding jobs for this user.
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
- public void onStopUser(int userHandle) {
+ public void onUserStopping(@NonNull TargetUser user) {
synchronized (mLock) {
- mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
+ mStartedUsers = ArrayUtils.removeInt(mStartedUsers, user.getUserIdentifier());
}
}
@@ -1193,7 +1194,7 @@
private void cancelJobsForNonExistentUsers() {
UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
synchronized (mLock) {
- mJobs.removeJobsOfNonUsers(umi.getUserIds());
+ mJobs.removeJobsOfUnlistedUsers(umi.getUserIds());
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 7bd51b7..eaf8f4d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -254,11 +254,11 @@
}
/**
- * Remove the jobs of users not specified in the whitelist.
- * @param whitelist Array of User IDs whose jobs are not to be removed.
+ * Remove the jobs of users not specified in the keepUserIds.
+ * @param keepUserIds Array of User IDs whose jobs should be kept and not removed.
*/
- public void removeJobsOfNonUsers(int[] whitelist) {
- mJobSet.removeJobsOfNonUsers(whitelist);
+ public void removeJobsOfUnlistedUsers(int[] keepUserIds) {
+ mJobSet.removeJobsOfUnlistedUsers(keepUserIds);
}
@VisibleForTesting
@@ -1151,15 +1151,14 @@
}
/**
- * Removes the jobs of all users not specified by the whitelist of user ids.
- * This will remove jobs scheduled *by* non-existent users as well as jobs scheduled *for*
- * non-existent users
+ * Removes the jobs of all users not specified by the keepUserIds of user ids.
+ * This will remove jobs scheduled *by* and *for* any unlisted users.
*/
- public void removeJobsOfNonUsers(final int[] whitelist) {
+ public void removeJobsOfUnlistedUsers(final int[] keepUserIds) {
final Predicate<JobStatus> noSourceUser =
- job -> !ArrayUtils.contains(whitelist, job.getSourceUserId());
+ job -> !ArrayUtils.contains(keepUserIds, job.getSourceUserId());
final Predicate<JobStatus> noCallingUser =
- job -> !ArrayUtils.contains(whitelist, job.getUserId());
+ job -> !ArrayUtils.contains(keepUserIds, job.getUserId());
removeAll(noSourceUser.or(noCallingUser));
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index b632435..44c8fcf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -91,9 +91,9 @@
pw.print(" from ");
UserHandle.formatUid(pw, uid);
pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
- if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
- mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
- pw.print(", whitelisted");
+ if (mAppStateTracker.isUidPowerSaveExempt(uid)
+ || mAppStateTracker.isUidTempPowerSaveExempt(uid)) {
+ pw.print(", exempted");
}
pw.print(": ");
pw.print(sourcePkg);
@@ -132,8 +132,8 @@
proto.write(TrackedJob.IS_IN_FOREGROUND, mAppStateTracker.isUidActive(sourceUid));
proto.write(TrackedJob.IS_WHITELISTED,
- mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
- mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
+ mAppStateTracker.isUidPowerSaveExempt(sourceUid)
+ || mAppStateTracker.isUidTempPowerSaveExempt(sourceUid));
proto.write(TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(sourceUid, sourcePkg));
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 2f993da..6bc95bf 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -222,12 +222,19 @@
@GuardedBy("mPackageAccessListeners")
private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
+ /**
+ * Lock specifically for bookkeeping around the carrier-privileged app set.
+ * Do not acquire any other locks while holding this one. Methods that
+ * require this lock to be held are named with a "CPL" suffix.
+ */
+ private final Object mCarrierPrivilegedLock = new Lock();
+
/** Whether we've queried the list of carrier privileged apps. */
- @GuardedBy("mAppIdleLock")
+ @GuardedBy("mCarrierPrivilegedLock")
private boolean mHaveCarrierPrivilegedApps;
/** List of carrier-privileged apps that should be excluded from standby */
- @GuardedBy("mAppIdleLock")
+ @GuardedBy("mCarrierPrivilegedLock")
private List<String> mCarrierPrivilegedApps;
@GuardedBy("mActiveAdminApps")
@@ -1594,9 +1601,9 @@
}
private boolean isCarrierApp(String packageName) {
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
if (!mHaveCarrierPrivilegedApps) {
- fetchCarrierPrivilegedAppsLocked();
+ fetchCarrierPrivilegedAppsCPL();
}
if (mCarrierPrivilegedApps != null) {
return mCarrierPrivilegedApps.contains(packageName);
@@ -1610,14 +1617,14 @@
if (DEBUG) {
Slog.i(TAG, "Clearing carrier privileged apps list");
}
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
mHaveCarrierPrivilegedApps = false;
mCarrierPrivilegedApps = null; // Need to be refetched.
}
}
- @GuardedBy("mAppIdleLock")
- private void fetchCarrierPrivilegedAppsLocked() {
+ @GuardedBy("mCarrierPrivilegedLock")
+ private void fetchCarrierPrivilegedAppsCPL() {
TelephonyManager telephonyManager =
mContext.getSystemService(TelephonyManager.class);
mCarrierPrivilegedApps =
@@ -1858,7 +1865,7 @@
@Override
public void dumpState(String[] args, PrintWriter pw) {
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ "): " + mCarrierPrivilegedApps);
}
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 04339e6..f66cf7c 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -30,6 +30,7 @@
"android/os/StatsDimensionsValueParcel.aidl",
"android/util/StatsEventParcel.aidl",
],
+ host_supported: true,
backend: {
java: {
enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
index 5cdb324..d56a4bd 100644
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
@@ -27,17 +27,6 @@
oneway void statsdReady();
/**
- * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
- * If anomaly alarm had already been registered, it will be replaced with the new timestamp.
- * Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and
- * alarm is inexact.
- */
- oneway void setAnomalyAlarm(long timestampMs);
-
- /** Cancel any anomaly detection alarm. */
- oneway void cancelAnomalyAlarm();
-
- /**
* Register a repeating alarm for pulling to fire at the given timestamp and every
* intervalMs thereafter (in ms since epoch).
* If polling alarm had already been registered, it will be replaced by new one.
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 0d3f420..066412a 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -42,13 +42,6 @@
void statsCompanionReady();
/**
- * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
- * act accordingly.
- * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
- */
- void informAnomalyAlarmFired();
-
- /**
* Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
* what stats to poll and initiating the polling.
* Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index cbc8ed6..b5e7224 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -100,7 +100,6 @@
private static IStatsd sStatsd;
private static final Object sStatsdLock = new Object();
- private final OnAlarmListener mAnomalyAlarmListener;
private final OnAlarmListener mPullingAlarmListener;
private final OnAlarmListener mPeriodicAlarmListener;
@@ -124,7 +123,6 @@
handlerThread.start();
mHandler = new CompanionHandler(handlerThread.getLooper());
- mAnomalyAlarmListener = new AnomalyAlarmListener(context);
mPullingAlarmListener = new PullingAlarmListener(context);
mPeriodicAlarmListener = new PeriodicAlarmListener(context);
}
@@ -336,41 +334,6 @@
}
}
- public static final class AnomalyAlarmListener implements OnAlarmListener {
- private final Context mContext;
-
- AnomalyAlarmListener(Context context) {
- mContext = context;
- }
-
- @Override
- public void onAlarm() {
- if (DEBUG) {
- Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
- + System.currentTimeMillis() + "ms.");
- }
- IStatsd statsd = getStatsdNonblocking();
- if (statsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
- return;
- }
-
- // Wakelock needs to be retained while calling statsd.
- Thread thread = new WakelockThread(mContext,
- AnomalyAlarmListener.class.getCanonicalName(), new Runnable() {
- @Override
- public void run() {
- try {
- statsd.informAnomalyAlarmFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
- }
- }
- });
- thread.start();
- }
- }
-
public final static class PullingAlarmListener implements OnAlarmListener {
private final Context mContext;
@@ -469,34 +432,6 @@
}
@Override // Binder call
- public void setAnomalyAlarm(long timestampMs) {
- StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs);
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
- // only fire when it awakens.
- // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm.
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly",
- mAnomalyAlarmListener, mHandler);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
- @Override // Binder call
- public void cancelAnomalyAlarm() {
- StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm");
- final long callingToken = Binder.clearCallingIdentity();
- try {
- mAlarmManager.cancel(mAnomalyAlarmListener);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
- @Override // Binder call
public void setAlarmForSubscriberTriggering(long timestampMs) {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
@@ -666,7 +601,6 @@
// instead of in binder death because statsd can come back and set different alarms, or not
// want to set an alarm when it had been set. This guarantees that when we get a new statsd,
// we cancel any alarms before it is able to set them.
- cancelAnomalyAlarm();
cancelPullingAlarm();
cancelAlarmForSubscriberTriggering();
diff --git a/api/current.txt b/api/current.txt
index 75ea7d7..a59c7b8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45455,6 +45455,7 @@
package android.telecom {
public final class Call {
+ method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void answer(int);
method public void conference(android.telecom.Call);
method public void deflect(android.net.Uri);
@@ -45563,6 +45564,7 @@
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static String propertiesToString(int);
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 33554432; // 0x2000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
@@ -45592,6 +45594,7 @@
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -45669,6 +45672,7 @@
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
+ method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -45684,6 +45688,9 @@
method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState();
+ method public final boolean isRingbackRequested();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
+ method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
@@ -45692,6 +45699,7 @@
method public void onMerge(android.telecom.Connection);
method public void onMerge();
method public void onPlayDtmfTone(char);
+ method public void onReject();
method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone();
method public void onSwap();
@@ -45712,6 +45720,8 @@
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold();
+ method public final void setRingbackRequested(boolean);
+ method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int);
@@ -45748,6 +45758,7 @@
method public final boolean isRingbackRequested();
method public final void notifyConferenceMergeFailed();
method public void onAbort();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
@@ -45827,6 +45838,7 @@
field public static final int AUDIO_CODEC_GSM_HR = 10; // 0xa
field public static final int AUDIO_CODEC_NONE = 0; // 0x0
field public static final int AUDIO_CODEC_QCELP13K = 3; // 0x3
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 67108864; // 0x4000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
@@ -45870,6 +45882,7 @@
field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -45965,9 +45978,13 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -46278,6 +46295,7 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
+ method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -46305,6 +46323,7 @@
method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
+ method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -46844,6 +46863,8 @@
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+ field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
+ field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
@@ -47916,12 +47937,13 @@
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
+ method @NonNull public android.telephony.SmsManager createForSubscriptionId(int);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method @NonNull public android.os.Bundle getCarrierConfigValues();
- method public static android.telephony.SmsManager getDefault();
+ method @Deprecated public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
- method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+ method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
method public int getSubscriptionId();
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c91c39a..3f3b8ea 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -31,6 +31,14 @@
}
+package android.media {
+
+ public class AudioManager {
+ field public static final int FLAG_FROM_KEY = 4096; // 0x1000
+ }
+
+}
+
package android.net {
public final class TetheringConstants {
@@ -77,6 +85,11 @@
method public final void markVintfStability();
}
+ public interface Parcelable {
+ field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
+ field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
+ }
+
public class StatsFrameworkInitializer {
method public static void registerServiceWrappers();
method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
diff --git a/api/test-current.txt b/api/test-current.txt
index 866b9383..963ef7c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -553,11 +553,13 @@
method public int getActivityType();
method public android.graphics.Rect getAppBounds();
method public android.graphics.Rect getBounds();
+ method @NonNull public android.graphics.Rect getMaxBounds();
method public int getRotation();
method public int getWindowingMode();
method public void setActivityType(int);
method public void setAppBounds(android.graphics.Rect);
method public void setBounds(android.graphics.Rect);
+ method public void setMaxBounds(@Nullable android.graphics.Rect);
method public void setRotation(int);
method public void setTo(android.app.WindowConfiguration);
method public void setWindowingMode(int);
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
index 02b27a8..403d8c5 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
@@ -29,4 +29,5 @@
const int ODM_PARTITION = 0x00000020;
const int OEM_PARTITION = 0x00000040;
const int ACTOR_SIGNATURE = 0x00000080;
+ const int CONFIG_SIGNATURE = 0x0000100;
}
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 34589a1..fd8b4eb 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,10 +61,13 @@
const ResourceId& target_resource) {
static constexpr const PolicyBitmask sDefaultPolicies =
PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
- PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
+ PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
+ PolicyFlags::CONFIG_SIGNATURE;
// If the resource does not have an overlayable definition, allow the resource to be overlaid if
- // the overlay is preinstalled or signed with the same signature as the target.
+ // the overlay is preinstalled, signed with the same signature as the target or signed with the
+ // same signature as reference package defined in SystemConfig under 'overlay-config-signature'
+ // tag.
if (!target_package.DefinesOverlayable()) {
return (sDefaultPolicies & fulfilled_policies) != 0
? Result<Unit>({})
diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index f7987b0..cdce451 100644
--- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -38,16 +38,18 @@
constexpr const char* kPolicyOem = "oem";
constexpr const char* kPolicyProduct = "product";
constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyConfigSignature = "config_signature";
constexpr const char* kPolicySignature = "signature";
constexpr const char* kPolicySystem = "system";
constexpr const char* kPolicyVendor = "vendor";
-inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = {
+inline static const std::array<std::pair<StringPiece, PolicyFlags>, 9> kPolicyStringToFlag = {
std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE},
{kPolicyOdm, PolicyFlags::ODM_PARTITION},
{kPolicyOem, PolicyFlags::OEM_PARTITION},
{kPolicyProduct, PolicyFlags::PRODUCT_PARTITION},
{kPolicyPublic, PolicyFlags::PUBLIC},
+ {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE},
{kPolicySignature, PolicyFlags::SIGNATURE},
{kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
{kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index 4f2ee1c..854b57f 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -43,16 +43,17 @@
constexpr ResourceId not_overlayable = 0x7f020003;
constexpr ResourceId other = 0x7f020004;
constexpr ResourceId policy_actor = 0x7f020005;
- constexpr ResourceId policy_odm = 0x7f020006;
- constexpr ResourceId policy_oem = 0x7f020007;
- constexpr ResourceId policy_product = 0x7f020008;
- constexpr ResourceId policy_public = 0x7f020009;
- constexpr ResourceId policy_signature = 0x7f02000a;
- constexpr ResourceId policy_system = 0x7f02000b;
- constexpr ResourceId policy_system_vendor = 0x7f02000c;
- constexpr ResourceId str1 = 0x7f02000d;
- constexpr ResourceId str3 = 0x7f02000f;
- constexpr ResourceId str4 = 0x7f020010;
+ constexpr ResourceId policy_config_signature = 0x7f020006;
+ constexpr ResourceId policy_odm = 0x7f020007;
+ constexpr ResourceId policy_oem = 0x7f020008;
+ constexpr ResourceId policy_product = 0x7f020009;
+ constexpr ResourceId policy_public = 0x7f02000a;
+ constexpr ResourceId policy_signature = 0x7f02000b;
+ constexpr ResourceId policy_system = 0x7f02000c;
+ constexpr ResourceId policy_system_vendor = 0x7f02000d;
+ constexpr ResourceId str1 = 0x7f02000e;
+ constexpr ResourceId str3 = 0x7f020010;
+ constexpr ResourceId str4 = 0x7f020011;
namespace literal { // NOLINT(runtime/indentation_namespace)
inline const std::string str1 = hexify(R::target::string::str1);
@@ -94,13 +95,14 @@
constexpr ResourceId not_overlayable = 0x7f010000;
constexpr ResourceId other = 0x7f010001;
constexpr ResourceId policy_actor = 0x7f010002;
- constexpr ResourceId policy_odm = 0x7f010003;
- constexpr ResourceId policy_oem = 0x7f010004;
- constexpr ResourceId policy_product = 0x7f010005;
- constexpr ResourceId policy_public = 0x7f010006;
- constexpr ResourceId policy_signature = 0x7f010007;
- constexpr ResourceId policy_system = 0x7f010008;
- constexpr ResourceId policy_system_vendor = 0x7f010009;
+ constexpr ResourceId policy_config_signature = 0x7f010003;
+ constexpr ResourceId policy_odm = 0x7f010004;
+ constexpr ResourceId policy_oem = 0x7f010005;
+ constexpr ResourceId policy_product = 0x7f010006;
+ constexpr ResourceId policy_public = 0x7f010007;
+ constexpr ResourceId policy_signature = 0x7f010008;
+ constexpr ResourceId policy_system = 0x7f010009;
+ constexpr ResourceId policy_system_vendor = 0x7f01000a;
} // namespace R::system_overlay_invalid::string
// clang-format on
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index de039f4..3ec6ac2 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -237,7 +237,7 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
- ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U);
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U);
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::not_overlayable,
false /* rewrite */));
@@ -256,6 +256,10 @@
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_public,
false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+ Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_config_signature,
+ false /* rewrite */));
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_signature,
false /* rewrite */));
@@ -298,8 +302,9 @@
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
}
-// Overlays that are pre-installed or are signed with the same signature as the target can overlay
-// packages that have not defined overlayable resources.
+// Overlays that are pre-installed or are signed with the same signature as the target or are signed
+// with the same signature as the reference package can overlay packages that have not defined
+// overlayable resources.
TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
@@ -309,7 +314,7 @@
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
- ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U);
ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::not_overlayable,
false /* rewrite */));
@@ -330,6 +335,10 @@
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_public,
false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature,
+ Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_config_signature,
+ false /* rewrite */));
ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_signature,
false /* rewrite */));
@@ -342,6 +351,7 @@
};
CheckEntries(PolicyFlags::SIGNATURE);
+ CheckEntries(PolicyFlags::CONFIG_SIGNATURE);
CheckEntries(PolicyFlags::PRODUCT_PARTITION);
CheckEntries(PolicyFlags::SYSTEM_PARTITION);
CheckEntries(PolicyFlags::VENDOR_PARTITION);
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
index 74ea18f..9641f6b5 100644
--- a/cmds/idmap2/tests/TestConstants.h
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -19,11 +19,11 @@
namespace android::idmap2::TestConstants {
-constexpr const auto TARGET_CRC = 0x41c60c8c;
-constexpr const auto TARGET_CRC_STRING = "41c60c8c";
+constexpr const auto TARGET_CRC = 0x7c2d4719;
+constexpr const auto TARGET_CRC_STRING = "7c2d4719";
-constexpr const auto OVERLAY_CRC = 0xc054fb26;
-constexpr const auto OVERLAY_CRC_STRING = "c054fb26";
+constexpr const auto OVERLAY_CRC = 0x5afff726;
+constexpr const auto OVERLAY_CRC_STRING = "5afff726";
} // namespace android::idmap2::TestConstants
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
index 7c25985..dab25b1 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index c75f3e1..c8b95c2 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
index 93dcc82..0a8b737 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
index 5b8a6e4..fd41182 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
index 698a1fd..b24765f 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk
index 1db303f..870575e 100644
--- a/cmds/idmap2/tests/data/overlay/overlay.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
index 51e19de..e0fd204 100644
--- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
+++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
index 7119d82..ebaf49c 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -26,6 +26,7 @@
<string name="policy_odm">policy_odm</string>
<string name="policy_oem">policy_oem</string>
<string name="policy_actor">policy_actor</string>
+ <string name="policy_config_signature">policy_config_signature</string>
<!-- Requests to overlay a resource that is not declared as overlayable. -->
<string name="not_overlayable">not_overlayable</string>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
index bd99098..a63daf8 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
index a0fba43..90d2803 100644
--- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index ad4cd48..57e6c43 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -45,6 +45,10 @@
<item type="string" name="policy_actor" />
</policy>
+ <policy type="config_signature">
+ <item type="string" name="policy_config_signature"/>
+ </policy>
+
<!-- Resources publicly overlayable -->
<policy type="public">
<item type="string" name="policy_public" />
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 5230e25..00909a9 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -37,6 +37,7 @@
<string name="policy_system">policy_system</string>
<string name="policy_system_vendor">policy_system_vendor</string>
<string name="policy_actor">policy_actor</string>
+ <string name="policy_config_signature">policy_config_signature</string>
<string name="other">other</string>
</resources>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index 58504a7..cc3491d 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index c80e5eb..4a58c5e 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 124f815f..1579715 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -171,7 +171,8 @@
export_generated_headers: ["statslog_statsdtest.h"],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
}
cc_library_static {
@@ -185,7 +186,11 @@
],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatspull",
+ ],
}
// =========
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 05e9ec3..6327490 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -120,10 +120,9 @@
}
}
-void StatsLogProcessor::onAnomalyAlarmFired(
+void StatsLogProcessor::processFiredAnomalyAlarmsLocked(
const int64_t& timestampNs,
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
- std::lock_guard<std::mutex> lock(mMetricsMutex);
for (const auto& itr : mMetricsManagers) {
itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
}
@@ -429,6 +428,20 @@
return;
}
+ bool fireAlarm = false;
+ {
+ std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex);
+ if (mNextAnomalyAlarmTime != 0 &&
+ MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) {
+ mNextAnomalyAlarmTime = 0;
+ VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs);
+ fireAlarm = true;
+ }
+ }
+ if (fireAlarm) {
+ informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs));
+ }
+
int64_t curTimeSec = getElapsedRealtimeSec();
if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
@@ -513,19 +526,34 @@
OnConfigUpdatedLocked(timestampNs, key, config);
}
-void StatsLogProcessor::OnConfigUpdatedLocked(
- const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config) {
+void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config, bool modularUpdate) {
VLOG("Updated configuration for key %s", key.ToString().c_str());
- sp<MetricsManager> newMetricsManager =
- new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager,
- mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
- if (newMetricsManager->isConfigValid()) {
- newMetricsManager->init();
- mUidMap->OnConfigUpdated(key);
- newMetricsManager->refreshTtl(timestampNs);
- mMetricsManagers[key] = newMetricsManager;
- VLOG("StatsdConfig valid");
+ // Create new config if this is not a modular update or if this is a new config.
+ const auto& it = mMetricsManagers.find(key);
+ bool configValid = false;
+ if (!modularUpdate || it == mMetricsManagers.end()) {
+ sp<MetricsManager> newMetricsManager =
+ new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager,
+ mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
+ configValid = newMetricsManager->isConfigValid();
+ if (configValid) {
+ newMetricsManager->init();
+ mUidMap->OnConfigUpdated(key);
+ newMetricsManager->refreshTtl(timestampNs);
+ mMetricsManagers[key] = newMetricsManager;
+ VLOG("StatsdConfig valid");
+ }
} else {
+ // Preserve the existing MetricsManager, update necessary components and metadata in place.
+ configValid = it->second->updateConfig(timestampNs, config);
+ if (configValid) {
+ // TODO(b/162323476): refresh TTL, ensure init() is handled properly.
+ mUidMap->OnConfigUpdated(key);
+
+ }
+ }
+ if (!configValid) {
// If there is any error in the config, don't use it.
// Remove any existing config with the same key.
ALOGE("StatsdConfig NOT valid");
@@ -1090,6 +1118,28 @@
mOnDiskDataConfigs.insert(key);
}
+void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) {
+ std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+ mNextAnomalyAlarmTime = elapsedTimeMillis;
+}
+
+void StatsLogProcessor::cancelAnomalyAlarm() {
+ std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+ mNextAnomalyAlarmTime = 0;
+}
+
+void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) {
+ VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
+ mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000));
+ if (alarmSet.size() > 0) {
+ VLOG("Found periodic alarm fired.");
+ processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet);
+ } else {
+ ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index c0f54a0..383dbd9 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -66,11 +66,6 @@
const DumpLatency dumpLatency,
ProtoOutputStream* proto);
- /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
- void onAnomalyAlarmFired(
- const int64_t& timestampNs,
- unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
-
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
void onPeriodicAlarmFired(
const int64_t& timestampNs,
@@ -146,6 +141,10 @@
// Add a specific config key to the possible configs to dump ASAP.
void noteOnDiskData(const ConfigKey& key);
+ void setAnomalyAlarm(const int64_t timeMillis);
+
+ void cancelAnomalyAlarm();
+
private:
// For testing only.
inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const {
@@ -158,6 +157,11 @@
mutable mutex mMetricsMutex;
+ // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled
+ // in the onLogEvent code path, which is locked by mMetricsMutex.
+ // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock.
+ mutable mutex mAnomalyAlarmMutex;
+
std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes;
@@ -183,8 +187,8 @@
void resetIfConfigTtlExpiredLocked(const int64_t timestampNs);
- void OnConfigUpdatedLocked(
- const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
+ void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key,
+ const StatsdConfig& config, bool modularUpdate = false);
void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
@@ -248,6 +252,15 @@
// Reset the specified configs.
void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs);
+ // An anomaly alarm should have fired.
+ // Check with anomaly alarm manager to find the alarms and process the result.
+ void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis);
+
+ /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
+ void processFiredAnomalyAlarmsLocked(
+ const int64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
+
// Function used to send a broadcast so that receiver for the config key can call getData
// to retrieve the stored data.
std::function<bool(const ConfigKey& key)> mSendBroadcast;
@@ -274,6 +287,9 @@
//Last time we wrote metadata to disk.
int64_t mLastMetadataWriteNs = 0;
+ // The time for the next anomaly alarm for alerts.
+ int64_t mNextAnomalyAlarmTime = 0;
+
bool mPrintAllLogs = false;
FRIEND_TEST(StatsLogProcessorTest, TestOutOfOrderLogs);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index d5e3314..68c2dd5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -91,17 +91,13 @@
StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
: mAnomalyAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
- [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) {
- if (sc != nullptr) {
- sc->setAnomalyAlarm(timeMillis);
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) {
+ mProcessor->setAnomalyAlarm(timeMillis);
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
},
- [](const shared_ptr<IStatsCompanionService>& sc) {
- if (sc != nullptr) {
- sc->cancelAnomalyAlarm();
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ [this](const shared_ptr<IStatsCompanionService>& /*sc*/) {
+ mProcessor->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
})),
mPeriodicAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
@@ -977,22 +973,6 @@
return Status::ok();
}
-Status StatsService::informAnomalyAlarmFired() {
- ENFORCE_UID(AID_SYSTEM);
-
- VLOG("StatsService::informAnomalyAlarmFired was called");
- int64_t currentTimeSec = getElapsedRealtimeSec();
- std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
- mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
- if (alarmSet.size() > 0) {
- VLOG("Found an anomaly alarm that fired.");
- mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
- } else {
- VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled.");
- }
- return Status::ok();
-}
-
Status StatsService::informAlarmForSubscriberTriggeringFired() {
ENFORCE_UID(AID_SYSTEM);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 324ffbd..479f4e8 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -66,7 +66,6 @@
virtual Status systemRunning();
virtual Status statsCompanionReady();
virtual Status bootCompleted();
- virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
virtual Status informAlarmForSubscriberTriggeringFired();
@@ -404,6 +403,10 @@
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket);
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket);
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket);
+
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
};
} // namespace statsd
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e70eac8..c95f4c0 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -66,7 +66,7 @@
import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto";
/**
- * The master atom class. This message defines all of the available
+ * The primary atom class. This message defines all of the available
* raw stats log events from the Android system, also known as "atoms."
*
* This field contains a single oneof with all of the available messages.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index bbae3fe..13020e0 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -128,7 +128,7 @@
}
void ConfigManager::StartupForTest() {
- // Dummy function to avoid reading configs from disks for tests.
+ // No-op function to avoid reading configs from disks for tests.
}
void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 40146b1..bef057f 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -46,7 +46,7 @@
void Startup();
/*
- * Dummy initializer for tests.
+ * No-op initializer for tests.
*/
void StartupForTest();
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 60de1a2..189d811 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -195,6 +195,10 @@
VLOG("~MetricsManager()");
}
+bool MetricsManager::updateConfig(const int64_t currentTimeNs, const StatsdConfig& config) {
+ return mConfigValid;
+}
+
void MetricsManager::initLogSourceWhiteList() {
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
mAllowedLogSources.clear();
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index ad30a88..042de29 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,6 +46,8 @@
virtual ~MetricsManager();
+ bool updateConfig(const int64_t currentTimeNs, const StatsdConfig& config);
+
// Return whether the configuration is valid.
bool isConfigValid() const;
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 6c50a8c..1bc84c5 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -17,6 +17,8 @@
#ifndef STATSD_PACKAGE_INFO_LISTENER_H
#define STATSD_PACKAGE_INFO_LISTENER_H
+#include <utils/RefBase.h>
+
#include <string>
namespace android {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 22250ae..622321b 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -17,7 +17,6 @@
#pragma once
#include "config/ConfigKey.h"
-#include "config/ConfigListener.h"
#include "packages/PackageInfoListener.h"
#include "stats_util.h"
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 26423d4..6264c07 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -13,9 +13,6 @@
// limitations under the License.
#include <gtest/gtest.h>
-#include <log/log_event_list.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
#include <stdio.h>
#include "annotations.h"
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index 95e3010..70e7365 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -12,14 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <android/binder_ibinder.h>
+#include <android/binder_interface_utils.h>
#include <gtest/gtest.h>
-#include "src/anomaly/DurationAnomalyTracker.h"
+#include <vector>
+
#include "src/StatsLogProcessor.h"
+#include "src/StatsService.h"
+#include "src/anomaly/DurationAnomalyTracker.h"
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
-#include <vector>
+using ::ndk::SharedRefBase;
namespace android {
namespace os {
@@ -29,6 +34,9 @@
namespace {
+const int kConfigKey = 789130124;
+const int kCallingUid = 0;
+
StatsdConfig CreateStatsdConfig(int num_buckets,
uint64_t threshold_ns,
DurationMetric::AggregationType aggregationType,
@@ -89,6 +97,13 @@
(int32_t)0x02010101), Value((int32_t)222))}),
DEFAULT_DIMENSION_KEY);
+void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
+ string str;
+ config.SerializeToString(&str);
+ std::vector<uint8_t> configAsVec(str.begin(), str.end());
+ service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
+}
+
} // namespace
TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
@@ -98,16 +113,18 @@
const uint64_t alert_id = config.alert(0).id();
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -158,12 +175,13 @@
const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
(uint32_t)alarmFiredTimestampSec0);
+ EXPECT_EQ(alarmFiredTimestampSec0,
+ processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec());
// Anomaly alarm fired.
- auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
- static_cast<uint32_t>(alarmFiredTimestampSec0));
- ASSERT_EQ(1u, alarmSet.size());
- processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+ auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC);
+ processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC);
+
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
@@ -179,39 +197,39 @@
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock wl1.
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
- attributionUids2, attributionTags2, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2,
+ attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
(uint64_t)alarmFiredTimestampSec1);
// Release wakelock wl1.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec1));
ASSERT_EQ(0u, alarmSet.size());
// Acquire wakelock wl1 near the end of bucket #0.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Release the event at early bucket #1.
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Anomaly detected when stopping the alarm. The refractory period does not change.
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
@@ -236,17 +254,17 @@
// Condition turns true.
screen_off_event =
- CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
+ CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
processor->OnLogEvent(screen_off_event.get());
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Condition turns to false.
- screen_on_event =
- CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
- android::view::DisplayStateEnum::DISPLAY_STATE_ON);
- processor->OnLogEvent(screen_on_event.get());
+ int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1;
+ screen_on_event = CreateScreenStateChangedEvent(
+ condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get(), condition_false_time);
// Condition turns to false. Cancelled the alarm.
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Detected one anomaly.
@@ -262,12 +280,11 @@
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
- attributionUids2, attributionTags2, "wl1");
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
processor->OnLogEvent(release_event.get());
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
}
@@ -279,16 +296,18 @@
const uint64_t alert_id = config.alert(0).id();
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -298,96 +317,97 @@
// Acquire wakelock "wc1" in bucket #0.
auto acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Release wakelock "wc1" in bucket #0.
- auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1;
+ auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock "wc1" in bucket #1.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
- attributionUids2, attributionTags2, "wl1");
+ acquire_event =
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1,
+ attributionUids2, attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock "wc2" in bucket #2.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
- attributionUids3, attributionTags3, "wl2");
+ acquire_event =
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1,
+ attributionUids3, attributionTags3, "wl2");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
// Release wakelock "wc2" in bucket #2.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
- attributionUids3, attributionTags3, "wl2");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
+ attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
// Acquire wakelock "wc1" in bucket #2.
acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC,
attributionUids2, attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Release wakelock "wc1" in bucket #2.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ(refractory_period_sec +
- (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
- NS_PER_SEC +
- 1,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
- attributionUids3, attributionTags3, "wl2");
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4,
+ attributionUids3, attributionTags3, "wl2");
processor->OnLogEvent(acquire_event.get());
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5,
+ attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
- attributionUids3, attributionTags3, "wl2");
- processor->OnLogEvent(release_event.get());
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
+ attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get(), release_event_time);
+ release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time + 4);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
// The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
- EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
+ EXPECT_EQ(refractory_period_sec +
+ (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) /
+ NS_PER_SEC +
1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
}
@@ -396,20 +416,22 @@
const int num_buckets = 2;
const uint64_t threshold_ns = 3 * NS_PER_SEC;
auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-
const uint64_t alert_id = config.alert(0).id();
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
+
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -418,81 +440,81 @@
processor->OnLogEvent(screen_off_event.get());
// Acquire wakelock "wc1" in bucket #0.
- auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
+ auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire the wakelock "wc1" again.
acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
// The alarm does not change.
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Anomaly alarm fired late.
- const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
- auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
- static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
- ASSERT_EQ(1u, alarmSet.size());
- processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+ const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+ auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs);
+ processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1;
+ auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Within the refractory period. No anomaly.
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// A new wakelock, but still within refractory period.
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
- attributionUids1, attributionTags1, "wl1");
+ release_event =
+ CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
// Still in the refractory period. No anomaly.
processor->OnLogEvent(release_event.get());
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index fed9c43..5f13a5c 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -69,6 +69,7 @@
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+ private static final String COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls";
/**
* Change the system dialer package name if a package name was specified,
@@ -119,6 +120,8 @@
+ "usage: telecom get-max-phones\n"
+ "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+ " provider after a call to emergency services.\n"
+ + "usage: telecom cleanup-stuck-calls: Clear any disconnected calls that have"
+ + " gotten wedged in Telecom.\n"
+ "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ "\n"
+ "telecom set-phone-account-enabled: Enables the given phone account, if it has"
@@ -214,6 +217,9 @@
case COMMAND_STOP_BLOCK_SUPPRESSION:
runStopBlockSuppression();
break;
+ case COMMAND_CLEANUP_STUCK_CALLS:
+ runCleanupStuckCalls();
+ break;
case COMMAND_SET_DEFAULT_DIALER:
runSetDefaultDialer();
break;
@@ -335,6 +341,10 @@
mTelecomService.stopBlockSuppression();
}
+ private void runCleanupStuckCalls() throws RemoteException {
+ mTelecomService.cleanupStuckCalls();
+ }
+
private void runSetDefaultDialer() throws RemoteException {
String packageName = nextArg();
if ("default".equals(packageName)) packageName = null;
diff --git a/cmds/uiautomator/api/current.txt b/cmds/uiautomator/api/current.txt
index 489c2ea..bf87d09 100644
--- a/cmds/uiautomator/api/current.txt
+++ b/cmds/uiautomator/api/current.txt
@@ -1,221 +1,222 @@
+// Signature format: 2.0
package com.android.uiautomator.core {
- public final deprecated class Configurator {
- method public long getActionAcknowledgmentTimeout();
- method public static com.android.uiautomator.core.Configurator getInstance();
- method public long getKeyInjectionDelay();
- method public long getScrollAcknowledgmentTimeout();
- method public long getWaitForIdleTimeout();
- method public long getWaitForSelectorTimeout();
- method public com.android.uiautomator.core.Configurator setActionAcknowledgmentTimeout(long);
- method public com.android.uiautomator.core.Configurator setKeyInjectionDelay(long);
- method public com.android.uiautomator.core.Configurator setScrollAcknowledgmentTimeout(long);
- method public com.android.uiautomator.core.Configurator setWaitForIdleTimeout(long);
- method public com.android.uiautomator.core.Configurator setWaitForSelectorTimeout(long);
+ @Deprecated public final class Configurator {
+ method @Deprecated public long getActionAcknowledgmentTimeout();
+ method @Deprecated public static com.android.uiautomator.core.Configurator getInstance();
+ method @Deprecated public long getKeyInjectionDelay();
+ method @Deprecated public long getScrollAcknowledgmentTimeout();
+ method @Deprecated public long getWaitForIdleTimeout();
+ method @Deprecated public long getWaitForSelectorTimeout();
+ method @Deprecated public com.android.uiautomator.core.Configurator setActionAcknowledgmentTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setKeyInjectionDelay(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setScrollAcknowledgmentTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setWaitForIdleTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setWaitForSelectorTimeout(long);
}
- public deprecated class UiCollection extends com.android.uiautomator.core.UiObject {
- ctor public UiCollection(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByInstance(com.android.uiautomator.core.UiSelector, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getChildCount(com.android.uiautomator.core.UiSelector);
+ @Deprecated public class UiCollection extends com.android.uiautomator.core.UiObject {
+ ctor @Deprecated public UiCollection(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByInstance(com.android.uiautomator.core.UiSelector, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getChildCount(com.android.uiautomator.core.UiSelector);
}
- public deprecated class UiDevice {
- method public void clearLastTraversedText();
- method public boolean click(int, int);
- method public boolean drag(int, int, int, int, int);
- method public void dumpWindowHierarchy(java.lang.String);
- method public void freezeRotation() throws android.os.RemoteException;
- method public deprecated java.lang.String getCurrentActivityName();
- method public java.lang.String getCurrentPackageName();
- method public int getDisplayHeight();
- method public int getDisplayRotation();
- method public android.graphics.Point getDisplaySizeDp();
- method public int getDisplayWidth();
- method public static com.android.uiautomator.core.UiDevice getInstance();
- method public java.lang.String getLastTraversedText();
- method public java.lang.String getProductName();
- method public boolean hasAnyWatcherTriggered();
- method public boolean hasWatcherTriggered(java.lang.String);
- method public boolean isNaturalOrientation();
- method public boolean isScreenOn() throws android.os.RemoteException;
- method public boolean openNotification();
- method public boolean openQuickSettings();
- method public boolean pressBack();
- method public boolean pressDPadCenter();
- method public boolean pressDPadDown();
- method public boolean pressDPadLeft();
- method public boolean pressDPadRight();
- method public boolean pressDPadUp();
- method public boolean pressDelete();
- method public boolean pressEnter();
- method public boolean pressHome();
- method public boolean pressKeyCode(int);
- method public boolean pressKeyCode(int, int);
- method public boolean pressMenu();
- method public boolean pressRecentApps() throws android.os.RemoteException;
- method public boolean pressSearch();
- method public void registerWatcher(java.lang.String, com.android.uiautomator.core.UiWatcher);
- method public void removeWatcher(java.lang.String);
- method public void resetWatcherTriggers();
- method public void runWatchers();
- method public void setCompressedLayoutHeirarchy(boolean);
- method public void setOrientationLeft() throws android.os.RemoteException;
- method public void setOrientationNatural() throws android.os.RemoteException;
- method public void setOrientationRight() throws android.os.RemoteException;
- method public void sleep() throws android.os.RemoteException;
- method public boolean swipe(int, int, int, int, int);
- method public boolean swipe(android.graphics.Point[], int);
- method public boolean takeScreenshot(java.io.File);
- method public boolean takeScreenshot(java.io.File, float, int);
- method public void unfreezeRotation() throws android.os.RemoteException;
- method public void waitForIdle();
- method public void waitForIdle(long);
- method public boolean waitForWindowUpdate(java.lang.String, long);
- method public void wakeUp() throws android.os.RemoteException;
+ @Deprecated public class UiDevice {
+ method @Deprecated public void clearLastTraversedText();
+ method @Deprecated public boolean click(int, int);
+ method @Deprecated public boolean drag(int, int, int, int, int);
+ method @Deprecated public void dumpWindowHierarchy(String);
+ method @Deprecated public void freezeRotation() throws android.os.RemoteException;
+ method @Deprecated public String getCurrentActivityName();
+ method @Deprecated public String getCurrentPackageName();
+ method @Deprecated public int getDisplayHeight();
+ method @Deprecated public int getDisplayRotation();
+ method @Deprecated public android.graphics.Point getDisplaySizeDp();
+ method @Deprecated public int getDisplayWidth();
+ method @Deprecated public static com.android.uiautomator.core.UiDevice getInstance();
+ method @Deprecated public String getLastTraversedText();
+ method @Deprecated public String getProductName();
+ method @Deprecated public boolean hasAnyWatcherTriggered();
+ method @Deprecated public boolean hasWatcherTriggered(String);
+ method @Deprecated public boolean isNaturalOrientation();
+ method @Deprecated public boolean isScreenOn() throws android.os.RemoteException;
+ method @Deprecated public boolean openNotification();
+ method @Deprecated public boolean openQuickSettings();
+ method @Deprecated public boolean pressBack();
+ method @Deprecated public boolean pressDPadCenter();
+ method @Deprecated public boolean pressDPadDown();
+ method @Deprecated public boolean pressDPadLeft();
+ method @Deprecated public boolean pressDPadRight();
+ method @Deprecated public boolean pressDPadUp();
+ method @Deprecated public boolean pressDelete();
+ method @Deprecated public boolean pressEnter();
+ method @Deprecated public boolean pressHome();
+ method @Deprecated public boolean pressKeyCode(int);
+ method @Deprecated public boolean pressKeyCode(int, int);
+ method @Deprecated public boolean pressMenu();
+ method @Deprecated public boolean pressRecentApps() throws android.os.RemoteException;
+ method @Deprecated public boolean pressSearch();
+ method @Deprecated public void registerWatcher(String, com.android.uiautomator.core.UiWatcher);
+ method @Deprecated public void removeWatcher(String);
+ method @Deprecated public void resetWatcherTriggers();
+ method @Deprecated public void runWatchers();
+ method @Deprecated public void setCompressedLayoutHeirarchy(boolean);
+ method @Deprecated public void setOrientationLeft() throws android.os.RemoteException;
+ method @Deprecated public void setOrientationNatural() throws android.os.RemoteException;
+ method @Deprecated public void setOrientationRight() throws android.os.RemoteException;
+ method @Deprecated public void sleep() throws android.os.RemoteException;
+ method @Deprecated public boolean swipe(int, int, int, int, int);
+ method @Deprecated public boolean swipe(android.graphics.Point[], int);
+ method @Deprecated public boolean takeScreenshot(java.io.File);
+ method @Deprecated public boolean takeScreenshot(java.io.File, float, int);
+ method @Deprecated public void unfreezeRotation() throws android.os.RemoteException;
+ method @Deprecated public void waitForIdle();
+ method @Deprecated public void waitForIdle(long);
+ method @Deprecated public boolean waitForWindowUpdate(String, long);
+ method @Deprecated public void wakeUp() throws android.os.RemoteException;
}
- public deprecated class UiObject {
- ctor public UiObject(com.android.uiautomator.core.UiSelector);
- method public void clearTextField() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean click() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickAndWaitForNewWindow() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickAndWaitForNewWindow(long) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean dragTo(com.android.uiautomator.core.UiObject, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean dragTo(int, int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean exists();
- method protected android.view.accessibility.AccessibilityNodeInfo findAccessibilityNodeInfo(long);
- method public android.graphics.Rect getBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChild(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getChildCount() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getClassName() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getContentDescription() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getFromParent(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getPackageName() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public final com.android.uiautomator.core.UiSelector getSelector();
- method public java.lang.String getText() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public android.graphics.Rect getVisibleBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isCheckable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isChecked() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isEnabled() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isFocusable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isFocused() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isLongClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isScrollable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isSelected() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClick() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords...);
- method public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
- method public boolean pinchIn(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean pinchOut(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean setText(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeDown(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeLeft(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeRight(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeUp(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean waitForExists(long);
- method public boolean waitUntilGone(long);
- field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
- field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
- field protected static final deprecated long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
- field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
- field protected static final deprecated long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
- field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ @Deprecated public class UiObject {
+ ctor @Deprecated public UiObject(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public void clearTextField() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean click() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickAndWaitForNewWindow() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickAndWaitForNewWindow(long) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean dragTo(com.android.uiautomator.core.UiObject, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean dragTo(int, int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean exists();
+ method @Deprecated protected android.view.accessibility.AccessibilityNodeInfo findAccessibilityNodeInfo(long);
+ method @Deprecated public android.graphics.Rect getBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChild(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getChildCount() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getClassName() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getContentDescription() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getFromParent(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getPackageName() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public final com.android.uiautomator.core.UiSelector getSelector();
+ method @Deprecated public String getText() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public android.graphics.Rect getVisibleBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isCheckable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isChecked() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isEnabled() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isFocusable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isFocused() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isLongClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isScrollable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isSelected() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClick() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...);
+ method @Deprecated public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
+ method @Deprecated public boolean pinchIn(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean pinchOut(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean setText(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeDown(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeLeft(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeRight(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeUp(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean waitForExists(long);
+ method @Deprecated public boolean waitUntilGone(long);
+ field @Deprecated protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field @Deprecated protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field @Deprecated protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
}
- public deprecated class UiObjectNotFoundException extends java.lang.Exception {
- ctor public UiObjectNotFoundException(java.lang.String);
- ctor public UiObjectNotFoundException(java.lang.String, java.lang.Throwable);
- ctor public UiObjectNotFoundException(java.lang.Throwable);
+ @Deprecated public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor @Deprecated public UiObjectNotFoundException(String);
+ ctor @Deprecated public UiObjectNotFoundException(String, Throwable);
+ ctor @Deprecated public UiObjectNotFoundException(Throwable);
}
- public deprecated class UiScrollable extends com.android.uiautomator.core.UiCollection {
- ctor public UiScrollable(com.android.uiautomator.core.UiSelector);
- method protected boolean exists(com.android.uiautomator.core.UiSelector);
- method public boolean flingBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, java.lang.String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, java.lang.String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getMaxSearchSwipes();
- method public double getSwipeDeadZonePercentage();
- method public boolean scrollBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollBackward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollDescriptionIntoView(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollForward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollIntoView(com.android.uiautomator.core.UiObject) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollIntoView(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollTextIntoView(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToBeginning(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToEnd(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiScrollable setAsHorizontalList();
- method public com.android.uiautomator.core.UiScrollable setAsVerticalList();
- method public com.android.uiautomator.core.UiScrollable setMaxSearchSwipes(int);
- method public com.android.uiautomator.core.UiScrollable setSwipeDeadZonePercentage(double);
+ @Deprecated public class UiScrollable extends com.android.uiautomator.core.UiCollection {
+ ctor @Deprecated public UiScrollable(com.android.uiautomator.core.UiSelector);
+ method @Deprecated protected boolean exists(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public boolean flingBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getMaxSearchSwipes();
+ method @Deprecated public double getSwipeDeadZonePercentage();
+ method @Deprecated public boolean scrollBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollBackward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollDescriptionIntoView(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollForward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollIntoView(com.android.uiautomator.core.UiObject) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollIntoView(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollTextIntoView(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToBeginning(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToEnd(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setAsHorizontalList();
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setAsVerticalList();
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setMaxSearchSwipes(int);
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setSwipeDeadZonePercentage(double);
}
- public deprecated class UiSelector {
- ctor public UiSelector();
- method public com.android.uiautomator.core.UiSelector checkable(boolean);
- method public com.android.uiautomator.core.UiSelector checked(boolean);
- method public com.android.uiautomator.core.UiSelector childSelector(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiSelector className(java.lang.String);
- method public <T> com.android.uiautomator.core.UiSelector className(java.lang.Class<T>);
- method public com.android.uiautomator.core.UiSelector classNameMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector clickable(boolean);
- method protected com.android.uiautomator.core.UiSelector cloneSelector();
- method public com.android.uiautomator.core.UiSelector description(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionContains(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionStartsWith(java.lang.String);
- method public com.android.uiautomator.core.UiSelector enabled(boolean);
- method public com.android.uiautomator.core.UiSelector focusable(boolean);
- method public com.android.uiautomator.core.UiSelector focused(boolean);
- method public com.android.uiautomator.core.UiSelector fromParent(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiSelector index(int);
- method public com.android.uiautomator.core.UiSelector instance(int);
- method public com.android.uiautomator.core.UiSelector longClickable(boolean);
- method public com.android.uiautomator.core.UiSelector packageName(java.lang.String);
- method public com.android.uiautomator.core.UiSelector packageNameMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector resourceId(java.lang.String);
- method public com.android.uiautomator.core.UiSelector resourceIdMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector scrollable(boolean);
- method public com.android.uiautomator.core.UiSelector selected(boolean);
- method public com.android.uiautomator.core.UiSelector text(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textContains(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textStartsWith(java.lang.String);
+ @Deprecated public class UiSelector {
+ ctor @Deprecated public UiSelector();
+ method @Deprecated public com.android.uiautomator.core.UiSelector checkable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector checked(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector childSelector(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiSelector className(String);
+ method @Deprecated public <T> com.android.uiautomator.core.UiSelector className(Class<T>);
+ method @Deprecated public com.android.uiautomator.core.UiSelector classNameMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector clickable(boolean);
+ method @Deprecated protected com.android.uiautomator.core.UiSelector cloneSelector();
+ method @Deprecated public com.android.uiautomator.core.UiSelector description(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionContains(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionStartsWith(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector enabled(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector focusable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector focused(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector fromParent(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiSelector index(int);
+ method @Deprecated public com.android.uiautomator.core.UiSelector instance(int);
+ method @Deprecated public com.android.uiautomator.core.UiSelector longClickable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector packageName(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector packageNameMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector resourceId(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector resourceIdMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector scrollable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector selected(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector text(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textContains(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textStartsWith(String);
}
- public abstract deprecated interface UiWatcher {
- method public abstract boolean checkForCondition();
+ @Deprecated public interface UiWatcher {
+ method @Deprecated public boolean checkForCondition();
}
}
package com.android.uiautomator.testrunner {
- public abstract deprecated interface IAutomationSupport {
- method public abstract void sendStatus(int, android.os.Bundle);
+ @Deprecated public interface IAutomationSupport {
+ method @Deprecated public void sendStatus(int, android.os.Bundle);
}
- public deprecated class UiAutomatorTestCase extends junit.framework.TestCase {
- ctor public UiAutomatorTestCase();
- method public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
- method public android.os.Bundle getParams();
- method public com.android.uiautomator.core.UiDevice getUiDevice();
- method public void sleep(long);
+ @Deprecated public class UiAutomatorTestCase extends junit.framework.TestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
+ method @Deprecated public android.os.Bundle getParams();
+ method @Deprecated public com.android.uiautomator.core.UiDevice getUiDevice();
+ method @Deprecated public void sleep(long);
}
}
diff --git a/cmds/uiautomator/api/removed.txt b/cmds/uiautomator/api/removed.txt
index e69de29..d802177 100644
--- a/cmds/uiautomator/api/removed.txt
+++ b/cmds/uiautomator/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index c33d31f..04b00cb 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-droiddoc {
- name: "uiautomator-stubs-docs",
+droidstubs {
+ name: "uiautomator-stubs",
srcs: [
"core-src/**/*.java",
"testrunner-src/**/*.java",
@@ -24,10 +24,10 @@
"android.test.base",
"unsupportedappusage",
],
- custom_template: "droiddoc-templates-sdk",
installable: false,
- args: "-stubpackages com.android.uiautomator.core:" +
- "com.android.uiautomator.testrunner",
+ flags: [
+ "-stubpackages com.android.uiautomator.core:com.android.uiautomator.testrunner",
+ ],
check_api: {
current: {
@@ -41,10 +41,26 @@
},
}
+droiddoc {
+ name: "uiautomator-stubs-docs",
+ srcs: [
+ ":uiautomator-stubs",
+ ],
+ libs: [
+ "android.test.runner",
+ "junit",
+ "android.test.base",
+ "unsupportedappusage",
+ ],
+ installable: false,
+ custom_template: "droiddoc-templates-sdk",
+ create_stubs: false,
+}
+
java_library_static {
name: "android_uiautomator",
srcs: [
- ":uiautomator-stubs-docs",
+ ":uiautomator-stubs",
],
libs: [
"android.test.runner",
@@ -64,7 +80,7 @@
],
static_libs: [
"junit",
- ]
+ ],
}
java_library_static {
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 71561c3..39248730 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -49,7 +49,7 @@
}
try {
if (isSet) {
- am.setActivityController(new DummyActivityController(), true);
+ am.setActivityController(new NoOpActivityController(), true);
} else {
am.setActivityController(null, true);
}
@@ -80,9 +80,9 @@
}
/**
- * Dummy, no interference, activity controller.
+ * No-op, no interference, activity controller.
*/
- private class DummyActivityController extends IActivityController.Stub {
+ private class NoOpActivityController extends IActivityController.Stub {
@Override
public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
/* do nothing and let activity proceed normally */
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
index d862e1c..e6fb7aa 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
@@ -45,7 +45,7 @@
public class UiAutomatorTestCase extends TestCase {
private static final String DISABLE_IME = "disable_ime";
- private static final String DUMMY_IME_PACKAGE = "com.android.testing.dummyime";
+ private static final String STUB_IME_PACKAGE = "com.android.testing.stubime";
private static final int NOT_A_SUBTYPE_ID = -1;
private UiDevice mUiDevice;
@@ -58,7 +58,7 @@
super.setUp();
mShouldDisableIme = "true".equals(mParams.getString(DISABLE_IME));
if (mShouldDisableIme) {
- setDummyIme();
+ setStubIme();
}
}
@@ -128,7 +128,7 @@
SystemClock.sleep(ms);
}
- private void setDummyIme() {
+ private void setStubIme() {
Context context = ActivityThread.currentApplication();
if (context == null) {
throw new RuntimeException("ActivityThread.currentApplication() is null.");
@@ -138,13 +138,13 @@
List<InputMethodInfo> infos = im.getInputMethodList();
String id = null;
for (InputMethodInfo info : infos) {
- if (DUMMY_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
+ if (STUB_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
id = info.getId();
}
}
if (id == null) {
throw new RuntimeException(String.format(
- "Required testing fixture missing: IME package (%s)", DUMMY_IME_PACKAGE));
+ "Required testing fixture missing: IME package (%s)", STUB_IME_PACKAGE));
}
if (context.checkSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 35cf39f..a9239b4 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -183,7 +183,7 @@
// This is to work around a bug in b/34736819. This needs to be removed once app team
// fixes their side.
- private AnimatorListenerAdapter mDummyListener = new AnimatorListenerAdapter() {
+ private AnimatorListenerAdapter mAnimationEndingListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mNodeMap.get(animation) == null) {
@@ -1186,7 +1186,7 @@
}
private void startAnimation() {
- addDummyListener();
+ addAnimationEndingListener();
// Register animation callback
addAnimationCallback(0);
@@ -1243,15 +1243,15 @@
// This is to work around the issue in b/34736819, as the old behavior in AnimatorSet had
// masked a real bug in play movies. TODO: remove this and below once the root cause is fixed.
- private void addDummyListener() {
+ private void addAnimationEndingListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.addListener(mDummyListener);
+ mNodes.get(i).mAnimation.addListener(mAnimationEndingListener);
}
}
- private void removeDummyListener() {
+ private void removeAnimationEndingListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.removeListener(mDummyListener);
+ mNodes.get(i).mAnimation.removeListener(mAnimationEndingListener);
}
}
@@ -1301,7 +1301,7 @@
tmpListeners.get(i).onAnimationEnd(this, mReversing);
}
}
- removeDummyListener();
+ removeAnimationEndingListener();
mSelfPulse = true;
mReversing = false;
}
@@ -1346,7 +1346,7 @@
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
anim.mEvents = new ArrayList<AnimationEvent>();
- anim.mDummyListener = new AnimatorListenerAdapter() {
+ anim.mAnimationEndingListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (anim.mNodeMap.get(animation) == null) {
@@ -1369,7 +1369,7 @@
final Node node = mNodes.get(n);
Node nodeClone = node.clone();
// Remove the old internal listener from the cloned child
- nodeClone.mAnimation.removeListener(mDummyListener);
+ nodeClone.mAnimation.removeListener(mAnimationEndingListener);
clonesMap.put(node, nodeClone);
anim.mNodes.add(nodeClone);
anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
@@ -2087,7 +2087,7 @@
* animation starts.
*/
public Builder after(long delay) {
- // setup dummy ValueAnimator just to run the clock
+ // setup a ValueAnimator just to run the clock
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(delay);
after(anim);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4a982dd..2be9282 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -35,6 +35,7 @@
import android.annotation.StyleRes;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.app.VoiceInteractor.Request;
import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
@@ -726,6 +727,7 @@
* upload, independent of whether the original activity is paused, stopped,
* or finished.
*/
+@UiContext
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index ef30cb4..7fe567b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -52,14 +52,23 @@
* if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
+ public static final int ALLOW_NON_FULL_IN_PROFILE_OR_FULL = 1;
public static final int ALLOW_FULL_ONLY = 2;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
* or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
+ public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL = 3;
+ /**
+ * Requires {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}, or
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in same profile group,
+ * otherwise {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. (so this is an extension
+ * to {@link #ALLOW_NON_FULL})
+ */
+ public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL = 4;
/**
* Verify that calling app has access to the given provider.
@@ -448,7 +457,7 @@
public abstract int broadcastIntent(Intent intent,
IIntentReceiver resultTo,
String[] requiredPermissions, boolean serialized,
- int userId, int[] appIdWhitelist);
+ int userId, int[] appIdAllowList);
/**
* Add uid to the ActivityManagerService PendingStartActivityUids list.
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 5e05506..9833ed6 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.StyleRes;
+import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -101,6 +102,7 @@
private final WindowManager mWindowManager;
@UnsupportedAppUsage
+ @UiContext
final Context mContext;
@UnsupportedAppUsage
final Window mWindow;
@@ -158,7 +160,7 @@
* @param context the context in which the dialog should run
* @see android.R.styleable#Theme_dialogTheme
*/
- public Dialog(@NonNull Context context) {
+ public Dialog(@UiContext @NonNull Context context) {
this(context, 0, true);
}
@@ -177,11 +179,12 @@
* @param themeResId a style resource describing the theme to use for the
* window, or {@code 0} to use the default dialog theme
*/
- public Dialog(@NonNull Context context, @StyleRes int themeResId) {
+ public Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId) {
this(context, themeResId, true);
}
- Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
+ Dialog(@UiContext @NonNull Context context, @StyleRes int themeResId,
+ boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (themeResId == Resources.ID_NULL) {
final TypedValue outValue = new TypedValue();
@@ -222,7 +225,7 @@
mCancelMessage = cancelCallback;
}
- protected Dialog(@NonNull Context context, boolean cancelable,
+ protected Dialog(@UiContext @NonNull Context context, boolean cancelable,
@Nullable OnCancelListener cancelListener) {
this(context);
mCancelable = cancelable;
@@ -234,7 +237,9 @@
*
* @return Context The Context used by the Dialog.
*/
- public final @NonNull Context getContext() {
+ @UiContext
+ @NonNull
+ public final Context getContext() {
return mContext;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c5d343d..0a80ccc 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -26,6 +26,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -213,7 +214,6 @@
private static final Object sSync = new Object[0];
@UnsupportedAppUsage
private static Globals sGlobals;
-
private final Context mContext;
private final boolean mWcgEnabled;
private final ColorManagementProxy mCmProxy;
@@ -539,7 +539,8 @@
}
}
- /*package*/ WallpaperManager(IWallpaperManager service, Context context, Handler handler) {
+ /*package*/ WallpaperManager(IWallpaperManager service, @UiContext Context context,
+ Handler handler) {
mContext = context;
if (service != null) {
initGlobals(service, context.getMainLooper());
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index ec81ae3..79f05a3 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -310,7 +310,6 @@
* Sets the maximum bounds to the provided {@link Rect}.
* @param rect the new bounds value.
* @see #getMaxBounds()
- * @hide
*/
public void setMaxBounds(@Nullable Rect rect) {
if (rect == null) {
@@ -364,10 +363,8 @@
return mBounds;
}
- /**
- * @see #setMaxBounds(Rect)
- * @hide
- */
+ /** @see #setMaxBounds(Rect) */
+ @NonNull
public Rect getMaxBounds() {
return mMaxBounds;
}
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index cb416c9..5f72bac 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UiContext;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Bundle;
@@ -42,6 +43,7 @@
* @see Context#createWindowContext(int, Bundle)
* @hide
*/
+@UiContext
public class WindowContext extends ContextWrapper {
private final WindowManagerImpl mWindowManager;
private final IWindowManager mWms;
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 20aa064..a789169 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -919,7 +919,7 @@
/**
* Only specialized platform agents should overload this entry point to support
- * restores to crazy non-app locations.
+ * restores to non-app locations.
* @hide
*/
protected void onRestoreFile(ParcelFileDescriptor data, long size,
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 4d73a61..f2a054d 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -229,7 +229,8 @@
}
/**
- * Get the total time this package spent in the foreground, measured in milliseconds.
+ * Get the total time this package spent in the foreground, measured in milliseconds. When in
+ * the foreground, the user is actively interacting with the app.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
@@ -237,6 +238,8 @@
/**
* Get the total time this package's activity is visible in the UI, measured in milliseconds.
+ * Note: An app may be visible but not considered foreground. Apps in the foreground must be
+ * visible, so visible time includes time in the foreground.
*/
public long getTotalTimeVisible() {
return mTotalTimeVisible;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 8a6cc95..1345e66 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -109,7 +109,7 @@
/**
- * The app is whitelisted for some reason and the bucket cannot be changed.
+ * The app is exempted for some reason and the bucket cannot be changed.
* {@hide}
*/
@SystemApi
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fb97468..fd60560 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1033,6 +1033,18 @@
}
/**
+ * Returns the anonymized hardware address of this BluetoothDevice. The first three octets
+ * will be suppressed for anonymization.
+ * <p> For example, "XX:XX:XX:AA:BB:CC".
+ *
+ * @return Anonymized bluetooth hardware address as string
+ * @hide
+ */
+ public String getAnonymizedAddress() {
+ return "XX:XX:XX" + getAddress().substring(8);
+ }
+
+ /**
* Get the friendly Bluetooth name of the remote device.
*
* <p>The local adapter will automatically retrieve remote names when
@@ -1482,7 +1494,7 @@
* present in the cache. Clients should use the {@link #getUuids} to get UUIDs
* if service discovery is not to be performed.
*
- * @return False if the sanity check fails, True if the process of initiating an ACL connection
+ * @return False if the check fails, True if the process of initiating an ACL connection
* to the remote device was started.
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
@@ -1516,7 +1528,7 @@
* The object type will match one of the SdpXxxRecord types, depending on the UUID searched
* for.
*
- * @return False if the sanity check fails, True if the process
+ * @return False if the check fails, True if the process
* of initiating an ACL connection to the remote device
* was started.
*/
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 60ecf64..33be50d 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1620,13 +1620,12 @@
* Implementation when a caller has performed an insert on the content
* provider, but that call has been rejected for the operation given
* to {@link #setAppOps(int, int)}. The default implementation simply
- * returns a dummy URI that is the base URI with a 0 path element
- * appended.
+ * returns a URI that is the base URI with a 0 path element appended.
*/
public Uri rejectInsert(Uri uri, ContentValues values) {
// If not allowed, we need to return some reasonable URI. Maybe the
// content provider should be responsible for this, but for now we
- // will just return the base URI with a dummy '0' tagged on to it.
+ // will just return the base URI with a '0' tagged on to it.
// You shouldn't be able to read if you can't write, anyway, so it
// shouldn't matter much what is returned.
return uri.buildUpon().appendPath("0").build();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 33f32fb..b5eb043 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -726,7 +726,7 @@
/**
* In addition to {@link #SYNC_EXEMPTION_PROMOTE_BUCKET}, we put the sync adapter app in the
- * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
+ * temp allowlist for 10 minutes, so that even RARE apps can run syncs right away.
* @hide
*/
public static final int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP = 2;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6f8923f..16cdf23 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -21,6 +21,7 @@
import android.annotation.CheckResult;
import android.annotation.ColorInt;
import android.annotation.ColorRes;
+import android.annotation.DisplayContext;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -33,6 +34,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IApplicationThread;
@@ -3750,6 +3752,7 @@
* @see #getSystemService(String)
* @see android.view.WindowManager
*/
+ @UiContext
public static final String WINDOW_SERVICE = "window";
/**
@@ -3760,6 +3763,7 @@
* @see #getSystemService(String)
* @see android.view.LayoutInflater
*/
+ @UiContext
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
/**
@@ -3932,6 +3936,7 @@
*
* @see #getSystemService(String)
*/
+ @UiContext
public static final String WALLPAPER_SERVICE = "wallpaper";
/**
@@ -5174,6 +5179,16 @@
public static final String DREAM_SERVICE = "dream";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.telephony.SmsManager} for accessing Sms functionality.
+ *
+ * @see #getSystemService(String)
+
+ * @hide
+ */
+ public static final String SMS_SERVICE = "sms";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
@@ -5779,6 +5794,7 @@
*
* @return A {@link Context} for the display.
*/
+ @DisplayContext
public abstract Context createDisplayContext(@NonNull Display display);
/**
@@ -5843,7 +5859,9 @@
* the current number of window contexts without adding any view by
* {@link WindowManager#addView} <b>exceeds five</b>.
*/
- public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
+ @UiContext
+ @NonNull
+ public Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index b72eb04..8d0baa7 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -273,7 +273,7 @@
totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll
- totalStats.numSourceOther
- totalStats.numSourceUser;
- if (totalStats.numSourcePeriodic < 0) { // Sanity check.
+ if (totalStats.numSourcePeriodic < 0) { // Consistency check.
totalStats.numSourcePeriodic = 0;
}
} else {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 72246ee..2006048 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -917,7 +917,7 @@
* Automatically detects if the package is a monolithic style (single APK
* file) or cluster style (directory of APKs).
* <p>
- * This performs sanity checking on cluster style packages, such as
+ * This performs checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
@@ -1038,7 +1038,7 @@
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
* <p>
- * This performs sanity checking on cluster style packages, such as
+ * This performs checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
* <p>
@@ -1072,7 +1072,7 @@
/**
* Parse all APKs contained in the given directory, treating them as a
- * single package. This also performs sanity checking, such as requiring
+ * single package. This also performs checking, such as requiring
* identical package name and version codes, a single base APK, and unique
* split names.
* <p>
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index cdb1d22..982fce9 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -147,7 +147,7 @@
/**
* Validate that the given file is a dex metadata archive.
- * This is just a sanity validation that the file is a zip archive.
+ * This is just a validation that the file is a zip archive.
*
* @throws PackageParserException if the file is not a .dm file.
*/
@@ -173,7 +173,7 @@
* (for any foo.dm there should be either a 'foo' of a 'foo.apk' file).
* If that's not the case it throws {@code IllegalStateException}.
*
- * This is used to perform a basic sanity check during adb install commands.
+ * This is used to perform a basic check during adb install commands.
* (The installer does not support stand alone .dm files)
*/
public static void validateDexPaths(String[] paths) {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 9480d36..6407f9b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1871,7 +1871,7 @@
*/
public boolean isOtherSeqNewer(Configuration other) {
if (other == null) {
- // Sanity check.
+ // Validation check.
return false;
}
if (other.seq == 0) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 7c4692c..0efd883 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -219,7 +219,7 @@
* even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
* The denial of service problem only comes into play when the pattern length gets
* into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
- * are at most a few dozen bytes in length, paranoid application developers may
+ * are at most a few dozen bytes in length, cautious application developers may
* want to reduce this parameter to something in the range of a few hundred
* if they know that external users are able to generate arbitrary patterns.
*/
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 2579ee6..da4d8e0 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -24,6 +24,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -39,6 +40,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -318,6 +321,37 @@
/** The HdmiControlService will be disabled to standby. */
public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
+ // -- Which devices the playback device can send a <Standby> message to upon going to sleep.
+ /**
+ * Send <Standby> to TV only.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_TO_TV = "to_tv";
+ /**
+ * Broadcast <Standby> to all devices in the network.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_BROADCAST = "broadcast";
+ /**
+ * Don't send any <Standby> message.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_NONE = "none";
+ /**
+ * @hide
+ */
+ @StringDef({
+ SEND_STANDBY_ON_SLEEP_TO_TV,
+ SEND_STANDBY_ON_SLEEP_BROADCAST,
+ SEND_STANDBY_ON_SLEEP_NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StandbyBehavior {
+ }
+
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c5a11abe..7250801 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -32,6 +32,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.Dialog;
import android.compat.annotation.UnsupportedAppUsage;
@@ -258,6 +259,7 @@
* @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
* @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
*/
+@UiContext
public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
static final boolean DEBUG = false;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ffb087f..5d4003a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -608,7 +608,7 @@
public static final int TYPE_BLUETOOTH = 7;
/**
- * Dummy data connection. This should not be used on shipping devices.
+ * Fake data connection. This should not be used on shipping devices.
* @deprecated This is not used any more.
*/
@Deprecated
@@ -1084,9 +1084,9 @@
* to remove an existing always-on VPN configuration.
* @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
* {@code false} otherwise.
- * @param lockdownWhitelist The list of packages that are allowed to access network directly
+ * @param lockdownAllowlist The list of packages that are allowed to access network directly
* when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
- * this method must be called when a package that should be whitelisted is installed or
+ * this method must be called when a package that should be allowed is installed or
* uninstalled.
* @return {@code true} if the package is set as always-on VPN controller;
* {@code false} otherwise.
@@ -1094,10 +1094,10 @@
*/
@RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
- boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
+ boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
try {
return mService.setAlwaysOnVpnPackage(
- userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
+ userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 482d2d2..327e42b 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -354,8 +354,7 @@
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with the type and an empty description.
- final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType,
- config.legacyTypeName, "");
+ final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
ni.setIsAvailable(true);
ni.setExtraInfo(config.getLegacyExtraInfo());
return ni;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index e449615..713b688 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -28,7 +28,7 @@
* @hide
*/
public class NetworkState implements Parcelable {
- private static final boolean SANITY_CHECK_ROAMING = false;
+ private static final boolean VALIDATE_ROAMING_STATE = false;
public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
@@ -52,7 +52,7 @@
// This object is an atomic view of a network, so the various components
// should always agree on roaming state.
- if (SANITY_CHECK_ROAMING && networkInfo != null && networkCapabilities != null) {
+ if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 3c1b86b..51f09a0 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,6 +26,7 @@
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.total;
@@ -364,11 +365,12 @@
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- final long fracRxBytes = rxBytes * overlap / duration;
- final long fracRxPackets = rxPackets * overlap / duration;
- final long fracTxBytes = txBytes * overlap / duration;
- final long fracTxPackets = txPackets * overlap / duration;
- final long fracOperations = operations * overlap / duration;
+ final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration);
+ final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration);
+ final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration);
+ final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration);
+ final long fracOperations = multiplySafeByRational(operations, overlap, duration);
+
addLong(activeTime, i, overlap);
addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
@@ -568,12 +570,24 @@
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketSpan;
- if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketSpan;
- if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketSpan;
- if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketSpan;
- if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketSpan;
- if (operations != null) entry.operations += operations[i] * overlap / bucketSpan;
+ if (activeTime != null) {
+ entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan);
+ }
+ if (rxBytes != null) {
+ entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan);
+ }
+ if (rxPackets != null) {
+ entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan);
+ }
+ if (txBytes != null) {
+ entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan);
+ }
+ if (txPackets != null) {
+ entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan);
+ }
+ if (operations != null) {
+ entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan);
+ }
}
return entry;
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 97a7ecc..1e5b6d5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -477,4 +477,35 @@
return true;
}
+
+ /**
+ * Safely multiple a value by a rational.
+ * <p>
+ * Internally it uses integer-based math whenever possible, but switches
+ * over to double-based math if values would overflow.
+ * @hide
+ */
+ public static long multiplySafeByRational(long value, long num, long den) {
+ if (den == 0) {
+ throw new ArithmeticException("Invalid Denominator");
+ }
+ long x = value;
+ long y = num;
+
+ // Logic shamelessly borrowed from Math.multiplyExact()
+ long r = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 != 0)) {
+ // Some bits greater than 2^31 that might cause overflow
+ // Check the result using the divide operator
+ // and check for the special case of Long.MIN_VALUE * -1
+ if (((y != 0) && (r / y != x)) ||
+ (x == Long.MIN_VALUE && y == -1)) {
+ // Use double math to avoid overflowing
+ return (long) (((double) num / den) * value);
+ }
+ }
+ return r / den;
+ }
}
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 8c6faf6..f6852e6 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -25,6 +25,7 @@
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Arrays;
/**
@@ -86,21 +87,26 @@
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
- * @param timeout network timeout in milliseconds.
+ * @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
+ * time, and it applies to each individual query to the resolved addresses of
+ * the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
- InetAddress address = null;
try {
- address = networkForResolv.getByName(host);
- } catch (Exception e) {
+ final InetAddress[] addresses = networkForResolv.getAllByName(host);
+ for (int i = 0; i < addresses.length; i++) {
+ if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+ }
+ } catch (UnknownHostException e) {
+ Log.w(TAG, "Unknown host: " + host);
EventLogTags.writeNtpFailure(host, e.toString());
- if (DBG) Log.d(TAG, "request time failed: " + e);
- return false;
}
- return requestTime(address, NTP_PORT, timeout, networkForResolv);
+
+ if (DBG) Log.d(TAG, "request time failed");
+ return false;
}
public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
@@ -139,10 +145,11 @@
final long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
final long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
final long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
+ final long referenceTime = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
- /* do sanity check according to RFC */
+ /* Do validation according to RFC */
// TODO: validate originateTime == requestTime.
- checkValidServerReply(leap, mode, stratum, transmitTime);
+ checkValidServerReply(leap, mode, stratum, transmitTime, referenceTime);
long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
// receiveTime = originateTime + transit + skew
@@ -218,7 +225,7 @@
}
private static void checkValidServerReply(
- byte leap, byte mode, int stratum, long transmitTime)
+ byte leap, byte mode, int stratum, long transmitTime, long referenceTime)
throws InvalidServerReplyException {
if (leap == NTP_LEAP_NOSYNC) {
throw new InvalidServerReplyException("unsynchronized server");
@@ -232,6 +239,9 @@
if (transmitTime == 0) {
throw new InvalidServerReplyException("zero transmitTime");
}
+ if (referenceTime == 0) {
+ throw new InvalidServerReplyException("zero reference timestamp");
+ }
}
/**
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 9c2c5b8..8e90a119 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -119,7 +119,7 @@
* <p> The Android system starts a VPN in the background by calling
* {@link android.content.Context#startService startService()}. In Android 8.0
* (API level 26) and higher, the system places VPN apps on the temporary
- * whitelist for a short period so the app can start in the background. The VPN
+ * allowlist for a short period so the app can start in the background. The VPN
* app must promote itself to the foreground after it's launched or the system
* will shut down the app.
*
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index bb8d4fe..3dce130 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -276,7 +276,7 @@
}
/**
- * Create a dummy instance for testing. All methods will fail unless
+ * Create an instance for testing. All methods will fail unless
* overridden with an appropriate mock implementation. To obtain a
* functional instance, use {@link android.content.Context#getSystemService}.
*/
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 87e7043..70c924a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1306,7 +1306,7 @@
/** {@hide} */
public static int translateModeStringToPosix(String mode) {
- // Sanity check for invalid chars
+ // Quick check for invalid chars
for (int i = 0; i < mode.length(); i++) {
switch (mode.charAt(i)) {
case 'r':
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index df58a6c..a6b869d 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -78,7 +78,7 @@
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
- private static final String GAME_DRIVER_WHITELIST_ALL = "*";
+ private static final String GAME_DRIVER_ALLOWLIST_ALL = "*";
private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
private static final int VULKAN_1_0 = 0x00400000;
private static final int VULKAN_1_1 = 0x00401000;
@@ -142,19 +142,19 @@
+ "set to: '" + devOptIn + "'");
}
- // We only want to use ANGLE if the app is whitelisted or the developer has
+ // We only want to use ANGLE if the app is allowlisted or the developer has
// explicitly chosen something other than default driver.
- // The whitelist will be generated by the ANGLE APK at both boot time and
+ // The allowlist will be generated by the ANGLE APK at both boot time and
// ANGLE update time. It will only include apps mentioned in the rules file.
- final boolean whitelisted = checkAngleWhitelist(context, coreSettings, packageName);
+ final boolean allowlisted = checkAngleAllowlist(context, coreSettings, packageName);
final boolean requested = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.ANGLE));
- final boolean useAngle = (whitelisted || requested);
+ final boolean useAngle = (allowlisted || requested);
if (!useAngle) {
return false;
}
- if (whitelisted) {
- Log.v(TAG, "ANGLE whitelist includes " + packageName);
+ if (allowlisted) {
+ Log.v(TAG, "ANGLE allowlist includes " + packageName);
}
if (requested) {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
@@ -564,17 +564,17 @@
}
/**
- * Pull ANGLE whitelist from GlobalSettings and compare against current package
+ * Pull ANGLE allowlist from GlobalSettings and compare against current package
*/
- private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
+ private static boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
final ContentResolver contentResolver = context.getContentResolver();
- final List<String> angleWhitelist =
+ final List<String> angleAllowlist =
getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST);
- if (DEBUG) Log.v(TAG, "ANGLE whitelist: " + angleWhitelist);
+ if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
- return angleWhitelist.contains(packageName);
+ return angleAllowlist.contains(packageName);
}
/**
@@ -584,7 +584,7 @@
* @param bundle
* @param packageName
* @return true: ANGLE setup successfully
- * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
+ * false: ANGLE not setup (not on allowlist, ANGLE not present, etc.)
*/
public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
String packageName) {
@@ -750,8 +750,8 @@
// 2. GAME_DRIVER_OPT_OUT_APPS
// 3. GAME_DRIVER_PRERELEASE_OPT_IN_APPS
// 4. GAME_DRIVER_OPT_IN_APPS
- // 5. GAME_DRIVER_BLACKLIST
- // 6. GAME_DRIVER_WHITELIST
+ // 5. GAME_DRIVER_DENYLIST
+ // 6. GAME_DRIVER_ALLOWLIST
switch (coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0)) {
case GAME_DRIVER_GLOBAL_OPT_IN_OFF:
if (DEBUG) Log.v(TAG, "Game Driver is turned off on this device.");
@@ -790,21 +790,21 @@
final boolean isOptIn =
getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
.contains(appPackageName);
- final List<String> whitelist =
- getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_WHITELIST);
- if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
- && !whitelist.contains(appPackageName)) {
- if (DEBUG) Log.v(TAG, "App is not on the whitelist for Game Driver.");
+ final List<String> allowlist =
+ getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_ALLOWLIST);
+ if (!isOptIn && allowlist.indexOf(GAME_DRIVER_ALLOWLIST_ALL) != 0
+ && !allowlist.contains(appPackageName)) {
+ if (DEBUG) Log.v(TAG, "App is not on the allowlist for Game Driver.");
return null;
}
- // If the application is not opted-in, then check whether it's on the blacklist,
- // terminate early if it's on the blacklist and fallback to system driver.
+ // If the application is not opted-in, then check whether it's on the denylist,
+ // terminate early if it's on the denylist and fallback to system driver.
if (!isOptIn
&& getGlobalSettingsString(
- null, coreSettings, Settings.Global.GAME_DRIVER_BLACKLIST)
+ null, coreSettings, Settings.Global.GAME_DRIVER_DENYLIST)
.contains(appPackageName)) {
- if (DEBUG) Log.v(TAG, "App is on the blacklist for Game Driver.");
+ if (DEBUG) Log.v(TAG, "App is on the denylist for Game Driver.");
return null;
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a7e3263..b05ea39 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -94,6 +94,11 @@
*/
private long mSlowDeliveryThresholdMs;
+ /**
+ * True if a message delivery takes longer than {@link #mSlowDeliveryThresholdMs}.
+ */
+ private boolean mSlowDeliveryDetected;
+
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
@@ -148,6 +153,105 @@
}
/**
+ * Poll and deliver single message, return true if the outer loop should continue.
+ */
+ private static boolean loopOnce(final Looper me,
+ final long ident, final int thresholdOverride) {
+ Message msg = me.mQueue.next(); // might block
+ if (msg == null) {
+ // No message indicates that the message queue is quitting.
+ return false;
+ }
+
+ // This must be in a local variable, in case a UI event sets the logger
+ final Printer logging = me.mLogging;
+ if (logging != null) {
+ logging.println(">>>>> Dispatching to " + msg.target + " "
+ + msg.callback + ": " + msg.what);
+ }
+ // Make sure the observer won't change while processing a transaction.
+ final Observer observer = sObserver;
+
+ final long traceTag = me.mTraceTag;
+ long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
+ long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
+ if (thresholdOverride > 0) {
+ slowDispatchThresholdMs = thresholdOverride;
+ slowDeliveryThresholdMs = thresholdOverride;
+ }
+ final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
+ final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
+
+ final boolean needStartTime = logSlowDelivery || logSlowDispatch;
+ final boolean needEndTime = logSlowDispatch;
+
+ if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
+ Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
+ }
+
+ final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
+ final long dispatchEnd;
+ Object token = null;
+ if (observer != null) {
+ token = observer.messageDispatchStarting();
+ }
+ long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
+ try {
+ msg.target.dispatchMessage(msg);
+ if (observer != null) {
+ observer.messageDispatched(token, msg);
+ }
+ dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
+ } catch (Exception exception) {
+ if (observer != null) {
+ observer.dispatchingThrewException(token, msg, exception);
+ }
+ throw exception;
+ } finally {
+ ThreadLocalWorkSource.restore(origWorkSource);
+ if (traceTag != 0) {
+ Trace.traceEnd(traceTag);
+ }
+ }
+ if (logSlowDelivery) {
+ if (me.mSlowDeliveryDetected) {
+ if ((dispatchStart - msg.when) <= 10) {
+ Slog.w(TAG, "Drained");
+ me.mSlowDeliveryDetected = false;
+ }
+ } else {
+ if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
+ msg)) {
+ // Once we write a slow delivery log, suppress until the queue drains.
+ me.mSlowDeliveryDetected = true;
+ }
+ }
+ }
+ if (logSlowDispatch) {
+ showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
+ }
+
+ if (logging != null) {
+ logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
+ }
+
+ // Make sure that during the course of dispatching the
+ // identity of the thread wasn't corrupted.
+ final long newIdent = Binder.clearCallingIdentity();
+ if (ident != newIdent) {
+ Log.wtf(TAG, "Thread identity changed from 0x"
+ + Long.toHexString(ident) + " to 0x"
+ + Long.toHexString(newIdent) + " while dispatching to "
+ + msg.target.getClass().getName() + " "
+ + msg.callback + " what=" + msg.what);
+ }
+
+ msg.recycleUnchecked();
+
+ return true;
+ }
+
+ /**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
@@ -162,7 +266,6 @@
}
me.mInLoop = true;
- final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
@@ -177,99 +280,12 @@
+ Thread.currentThread().getName()
+ ".slow", 0);
- boolean slowDeliveryDetected = false;
+ me.mSlowDeliveryDetected = false;
for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
+ if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
-
- // This must be in a local variable, in case a UI event sets the logger
- final Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- // Make sure the observer won't change while processing a transaction.
- final Observer observer = sObserver;
-
- final long traceTag = me.mTraceTag;
- long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
- long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
- if (thresholdOverride > 0) {
- slowDispatchThresholdMs = thresholdOverride;
- slowDeliveryThresholdMs = thresholdOverride;
- }
- final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
- final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
-
- final boolean needStartTime = logSlowDelivery || logSlowDispatch;
- final boolean needEndTime = logSlowDispatch;
-
- if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
- Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
- }
-
- final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
- final long dispatchEnd;
- Object token = null;
- if (observer != null) {
- token = observer.messageDispatchStarting();
- }
- long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
- try {
- msg.target.dispatchMessage(msg);
- if (observer != null) {
- observer.messageDispatched(token, msg);
- }
- dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
- } catch (Exception exception) {
- if (observer != null) {
- observer.dispatchingThrewException(token, msg, exception);
- }
- throw exception;
- } finally {
- ThreadLocalWorkSource.restore(origWorkSource);
- if (traceTag != 0) {
- Trace.traceEnd(traceTag);
- }
- }
- if (logSlowDelivery) {
- if (slowDeliveryDetected) {
- if ((dispatchStart - msg.when) <= 10) {
- Slog.w(TAG, "Drained");
- slowDeliveryDetected = false;
- }
- } else {
- if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
- msg)) {
- // Once we write a slow delivery log, suppress until the queue drains.
- slowDeliveryDetected = true;
- }
- }
- }
- if (logSlowDispatch) {
- showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
- }
-
- if (logging != null) {
- logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
- }
-
- // Make sure that during the course of dispatching the
- // identity of the thread wasn't corrupted.
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf(TAG, "Thread identity changed from 0x"
- + Long.toHexString(ident) + " to 0x"
- + Long.toHexString(newIdent) + " while dispatching to "
- + msg.target.getClass().getName() + " "
- + msg.callback + " what=" + msg.what);
- }
-
- msg.recycleUnchecked();
}
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 0ec4fb8..40c291f 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -16,6 +16,6 @@
per-file PowerManagerInternal.java = michaelwr@google.com, santoscordon@google.com
# Zygote
-per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file ZygoteProcess.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
per-file GraphicsEnvironment.java = chrisforbes@google.com, cnorthrop@google.com, lpy@google.com, timvp@google.com, zzyiwei@google.com
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index bedbba0..3d3759e 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -119,6 +120,7 @@
* @see ParcelableHolder
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int PARCELABLE_STABILITY_LOCAL = 0x0000;
/**
* Something that is meant to be used between system and vendor.
@@ -126,6 +128,7 @@
* @see ParcelableHolder
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int PARCELABLE_STABILITY_VINTF = 0x0001;
/**
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index f4645ca..39c196d 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -1,6 +1,14 @@
{
"presubmit": [
- // TODO(159590499) add BugreportManagerTestCases
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
{
"file_patterns": ["Bugreport[^/]*\\.java"],
"name": "CtsBugreportTestCases",
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 39038f5..ffede09 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -251,11 +251,11 @@
private final Object mLock = new Object();
/**
- * List of exemptions to the API blacklist. These are prefix matches on the runtime format
+ * List of exemptions to the API deny list. These are prefix matches on the runtime format
* symbol signature. Any matching symbol is treated by the runtime as being on the light grey
* list.
*/
- private List<String> mApiBlacklistExemptions = Collections.emptyList();
+ private List<String> mApiDenylistExemptions = Collections.emptyList();
/**
* Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
@@ -562,7 +562,7 @@
"--preload-package",
"--preload-app",
"--start-child-zygote",
- "--set-api-blacklist-exemptions",
+ "--set-api-denylist-exemptions",
"--hidden-api-log-sampling-rate",
"--hidden-api-statslog-sampling-rate",
"--invoke-with"
@@ -922,20 +922,20 @@
}
/**
- * Push hidden API blacklisting exemptions into the zygote process(es).
+ * Push hidden API deny-listing exemptions into the zygote process(es).
*
* <p>The list of exemptions will take affect for all new processes forked from the zygote after
* this call.
*
* @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
- * whitelisted/public APIs (i.e. allowed, no logging of usage).
+ * allowed/public APIs (i.e. allowed, no logging of usage).
*/
- public boolean setApiBlacklistExemptions(List<String> exemptions) {
+ public boolean setApiDenylistExemptions(List<String> exemptions) {
synchronized (mLock) {
- mApiBlacklistExemptions = exemptions;
- boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
+ mApiDenylistExemptions = exemptions;
+ boolean ok = maybeSetApiDenylistExemptions(primaryZygoteState, true);
if (ok) {
- ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
+ ok = maybeSetApiDenylistExemptions(secondaryZygoteState, true);
}
return ok;
}
@@ -972,32 +972,32 @@
}
@GuardedBy("mLock")
- private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
+ private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty) {
if (state == null || state.isClosed()) {
- Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
+ Slog.e(LOG_TAG, "Can't set API denylist exemptions: no zygote connection");
return false;
- } else if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
+ } else if (!sendIfEmpty && mApiDenylistExemptions.isEmpty()) {
return true;
}
try {
- state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
+ state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
state.mZygoteOutputWriter.newLine();
- state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
+ state.mZygoteOutputWriter.write("--set-api-denylist-exemptions");
state.mZygoteOutputWriter.newLine();
- for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
- state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
+ for (int i = 0; i < mApiDenylistExemptions.size(); ++i) {
+ state.mZygoteOutputWriter.write(mApiDenylistExemptions.get(i));
state.mZygoteOutputWriter.newLine();
}
state.mZygoteOutputWriter.flush();
int status = state.mZygoteInputStream.readInt();
if (status != 0) {
- Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions; status " + status);
}
return true;
} catch (IOException ioe) {
- Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
- mApiBlacklistExemptions = Collections.emptyList();
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions", ioe);
+ mApiDenylistExemptions = Collections.emptyList();
return false;
}
}
@@ -1054,7 +1054,7 @@
primaryZygoteState =
ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
- maybeSetApiBlacklistExemptions(primaryZygoteState, false);
+ maybeSetApiDenylistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
}
@@ -1069,7 +1069,7 @@
ZygoteState.connect(mZygoteSecondarySocketAddress,
mUsapPoolSecondarySocketAddress);
- maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
+ maybeSetApiDenylistExemptions(secondaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
old mode 100755
new mode 100644
index 346522a..7ee41b9
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9794,6 +9794,21 @@
"hdmi_control_auto_device_off_enabled";
/**
+ * Property to decide which devices the playback device can send a <Standby> message to upon
+ * going to sleep. Supported values are:
+ * <ul>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_TO_TV} to TV only.</li>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_BROADCAST} to all devices in the
+ * network.</li>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_NONE} no <Standby> message sent.</li>
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_SEND_STANDBY_ON_SLEEP =
+ "hdmi_control_send_standby_on_sleep";
+
+ /**
* Whether or not media is shown automatically when bypassing as a heads up.
* @hide
*/
@@ -10840,17 +10855,6 @@
public static final String MODE_RINGER = "mode_ringer";
/**
- * Specifies whether Enhanced Connectivity is enabled or not. This setting allows the
- * Connectivity Thermal Power Manager to actively help the device to save power in 5G
- * scenarios
- * Type: int 1 is enabled, 0 is disabled
- *
- * @hide
- */
- public static final String ENHANCED_CONNECTIVITY_ENABLED =
- "enhanced_connectivity_enable";
-
- /**
* Overlay display devices setting.
* The associated value is a specially formatted string that describes the
* size and density of simulated secondary display devices.
@@ -12334,8 +12338,8 @@
* List of package names that should check ANGLE rules
* @hide
*/
- public static final String GLOBAL_SETTINGS_ANGLE_WHITELIST =
- "angle_whitelist";
+ public static final String GLOBAL_SETTINGS_ANGLE_ALLOWLIST =
+ "angle_allowlist";
/**
* Show the "ANGLE In Use" dialog box to the user when ANGLE is the OpenGL driver.
@@ -12377,24 +12381,24 @@
public static final String GAME_DRIVER_OPT_OUT_APPS = "game_driver_opt_out_apps";
/**
- * Apps on the blacklist that are forbidden to use Game Driver.
+ * Apps on the denylist that are forbidden to use Game Driver.
* @hide
*/
- public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
+ public static final String GAME_DRIVER_DENYLIST = "game_driver_denylist";
/**
- * List of blacklists, each blacklist is a blacklist for a specific version of Game Driver.
+ * List of denylists, each denylist is a denylist for a specific version of Game Driver.
* @hide
*/
- public static final String GAME_DRIVER_BLACKLISTS = "game_driver_blacklists";
+ public static final String GAME_DRIVER_DENYLISTS = "game_driver_denylists";
/**
- * Apps on the whitelist that are allowed to use Game Driver.
+ * Apps on the allowlist that are allowed to use Game Driver.
* The string is a list of application package names, seperated by comma.
* i.e. <apk1>,<apk2>,...,<apkN>
* @hide
*/
- public static final String GAME_DRIVER_WHITELIST = "game_driver_whitelist";
+ public static final String GAME_DRIVER_ALLOWLIST = "game_driver_allowlist";
/**
* List of libraries in sphal accessible by Game Driver
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 57068fa..00872fb 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -216,7 +216,7 @@
* in {@link Builder#build()}, recursively if needed.
*/
public Builder setParent(Builder parent) {
- // Sanity check to avoid adding loops.
+ // Quick check to avoid adding loops.
Builder current = parent;
while (current != null) {
if (current == this) {
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 8be114c..2cd8b8b 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -73,6 +73,11 @@
* Notification has been dismissed from the notification shade.
*/
public static final int DISMISSAL_SHADE = 3;
+ /**
+ * Notification has been dismissed as a bubble.
+ * @hide
+ */
+ public static final int DISMISSAL_BUBBLE = 3;
/** @hide */
@IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = {
diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java
index de9ec7a..e8236fd 100644
--- a/core/java/android/text/format/DateIntervalFormat.java
+++ b/core/java/android/text/format/DateIntervalFormat.java
@@ -62,7 +62,7 @@
/**
* Format a date range. This is our slightly more sensible internal API.
- * A truly sane replacement would take a skeleton instead of int flags.
+ * A truly reasonable replacement would take a skeleton instead of int flags.
*/
@VisibleForTesting(visibility = PACKAGE)
public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone,
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index cbe3734..aa70d07 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -96,7 +96,7 @@
private byte mState = 0;
/**
- * Keeps track of the currently read nested Objects, for end object sanity checking and debug
+ * Keeps track of the currently read nested Objects, for end object checking and debug
*/
private ArrayList<Long> mExpectedObjectTokenStack = null;
@@ -513,7 +513,7 @@
(int) fieldId, getOffset() + messageSize));
}
- // Sanity check
+ // Validation check
if (mDepth > 0
&& getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth))
> getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth - 1))) {
@@ -536,7 +536,7 @@
* @param token - token
*/
public void end(long token) {
- // Sanity check to make sure user is keeping track of their embedded messages
+ // Make sure user is keeping track of their embedded messages
if (mExpectedObjectTokenStack.get(mDepth) != token) {
throw new ProtoParseException(
"end token " + token + " does not match current message token "
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 5fcd38e..afca4ab 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -59,10 +59,10 @@
* cache the size, and then write the size-prefixed buffers.
*
* We are trying to avoid too much generated code here, but this class still
- * needs to have a somewhat sane API. We can't have the multiple passes be
- * done by the calling code. In addition, we want to avoid the memory high
- * water mark of duplicating all of the values into the traditional in-memory
- * Message objects. We need to find another way.
+ * needs to have API. We can't have the multiple passes be done by the
+ * calling code. In addition, we want to avoid the memory high water mark
+ * of duplicating all of the values into the traditional in-memory Message
+ * objects. We need to find another way.
*
* So what we do here is to let the calling code write the data into a
* byte[] (actually a collection of them wrapped in the EncodedBuffer class),
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0cc469a..c4048e5 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,7 @@
import android.annotation.TestApi;
import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1157,9 +1158,19 @@
* </p><p>
* The real size may be smaller than the physical size of the screen when the
* window manager is emulating a smaller display (using adb shell wm size).
- * </p>
+ * </p><p>
+ * In general, {@link #getRealSize(Point)} and {@link WindowManager#getMaximumWindowMetrics()}
+ * report the same bounds except that certain areas of the display may not be available to
+ * windows created in the {@link WindowManager}'s {@link Context}.
+ *
+ * For example, imagine a device which has a multi-task mode that limits windows to half of the
+ * screen. In this case, {@link WindowManager#getMaximumWindowMetrics()} reports the
+ * bounds of the screen half where the window is located, while {@link #getRealSize(Point)}
+ * still reports the bounds of the whole display.
*
* @param outSize Set to the real size of the display.
+ *
+ * @see WindowManager#getMaximumWindowMetrics()
*/
public void getRealSize(Point outSize) {
synchronized (this) {
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 713cfb4..064bc69 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -311,6 +311,9 @@
}
final int count = focusables.size();
+ if (count < 2) {
+ return null;
+ }
switch (direction) {
case View.FOCUS_FORWARD:
return getNextFocusable(focused, focusables, count);
@@ -373,29 +376,29 @@
}
private static View getNextFocusable(View focused, ArrayList<View> focusables, int count) {
+ if (count < 2) {
+ return null;
+ }
if (focused != null) {
int position = focusables.lastIndexOf(focused);
if (position >= 0 && position + 1 < count) {
return focusables.get(position + 1);
}
}
- if (!focusables.isEmpty()) {
- return focusables.get(0);
- }
- return null;
+ return focusables.get(0);
}
private static View getPreviousFocusable(View focused, ArrayList<View> focusables, int count) {
+ if (count < 2) {
+ return null;
+ }
if (focused != null) {
int position = focusables.indexOf(focused);
if (position > 0) {
return focusables.get(position - 1);
}
}
- if (!focusables.isEmpty()) {
- return focusables.get(count - 1);
- }
- return null;
+ return focusables.get(count - 1);
}
private static View getNextKeyboardNavigationCluster(
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 55c527b..8a72218 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -25,6 +25,7 @@
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
+import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
@@ -393,7 +394,7 @@
*
* @throws NullPointerException if {@code listener} is null.
*/
- public GestureDetector(Context context, OnGestureListener listener) {
+ public GestureDetector(@UiContext Context context, OnGestureListener listener) {
this(context, listener, null);
}
@@ -412,7 +413,8 @@
*
* @throws NullPointerException if {@code listener} is null.
*/
- public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
+ public GestureDetector(@UiContext Context context, OnGestureListener listener,
+ Handler handler) {
if (handler != null) {
mHandler = new GestureHandler(handler);
} else {
@@ -442,12 +444,12 @@
*
* @throws NullPointerException if {@code listener} is null.
*/
- public GestureDetector(Context context, OnGestureListener listener, Handler handler,
+ public GestureDetector(@UiContext Context context, OnGestureListener listener, Handler handler,
boolean unused) {
this(context, listener, handler);
}
- private void init(Context context) {
+ private void init(@UiContext Context context) {
if (mListener == null) {
throw new NullPointerException("OnGestureListener must not be null");
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1afe11e..b925b49 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -94,6 +95,7 @@
* {@hide}
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UiContext
protected final Context mContext;
// these are optional, set by the caller
@@ -277,7 +279,7 @@
/**
* Obtains the LayoutInflater from the given context.
*/
- public static LayoutInflater from(Context context) {
+ public static LayoutInflater from(@UiContext Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ecf9774..8cb8e1d 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
import android.graphics.ColorSpace;
@@ -1001,7 +1002,10 @@
mHardwareRenderer = new HardwareRenderer();
mHardwareRenderer.setContentRoot(mRenderNode);
mHardwareRenderer.setSurface(Surface.this, true);
- mHardwareRenderer.setWideGamut(isWideColorGamut);
+ mHardwareRenderer.setColorMode(
+ isWideColorGamut
+ ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
+ : ActivityInfo.COLOR_MODE_DEFAULT);
mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6beea876..eaa7eaf 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -595,6 +595,256 @@
}
/**
+ * A common arguments class used for various screenshot requests. This contains arguments that
+ * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
+ * @hide
+ */
+ public abstract static class CaptureArgs {
+ private final int mPixelFormat;
+ private final Rect mSourceCrop = new Rect();
+ private final float mFrameScale;
+ private final boolean mCaptureSecureLayers;
+
+ private CaptureArgs(Builder<? extends Builder<?>> builder) {
+ mPixelFormat = builder.mPixelFormat;
+ mSourceCrop.set(builder.mSourceCrop);
+ mFrameScale = builder.mFrameScale;
+ mCaptureSecureLayers = builder.mCaptureSecureLayers;
+ }
+
+ /**
+ * The Builder class used to construct {@link CaptureArgs}
+ *
+ * @param <T> A builder that extends {@link Builder}
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ private int mPixelFormat = PixelFormat.RGBA_8888;
+ private final Rect mSourceCrop = new Rect();
+ private float mFrameScale = 1;
+ private boolean mCaptureSecureLayers;
+
+ /**
+ * The desired pixel format of the returned buffer.
+ */
+ public T setPixelFormat(int pixelFormat) {
+ mPixelFormat = pixelFormat;
+ return getThis();
+ }
+
+ /**
+ * The portion of the screen to capture into the buffer. Caller may pass in
+ * 'new Rect()' if no cropping is desired.
+ */
+ public T setSourceCrop(Rect sourceCrop) {
+ mSourceCrop.set(sourceCrop);
+ return getThis();
+ }
+
+ /**
+ * The desired scale of the returned buffer. The raw screen will be scaled up/down.
+ */
+ public T setFrameScale(float frameScale) {
+ mFrameScale = frameScale;
+ return getThis();
+ }
+
+ /**
+ * Whether to allow the screenshot of secure layers. Warning: This should only be done
+ * if the content will be placed in a secure SurfaceControl.
+ *
+ * @see ScreenshotHardwareBuffer#containsSecureLayers()
+ */
+ public T setCaptureSecureLayers(boolean captureSecureLayers) {
+ mCaptureSecureLayers = captureSecureLayers;
+ return getThis();
+ }
+
+ /**
+ * Each sub class should return itself to allow the builder to chain properly
+ */
+ public abstract T getThis();
+ }
+ }
+
+ /**
+ * The arguments class used to make display capture requests.
+ *
+ * @see #nativeScreenshot(IBinder, Rect, int, int, boolean, int, boolean)
+ * @hide
+ */
+ public static class DisplayCaptureArgs extends CaptureArgs {
+ private final IBinder mDisplayToken;
+ private final int mWidth;
+ private final int mHeight;
+ private final boolean mUseIdentityTransform;
+ private final int mRotation;
+
+ private DisplayCaptureArgs(Builder builder) {
+ super(builder);
+ mDisplayToken = builder.mDisplayToken;
+ mWidth = builder.mWidth;
+ mHeight = builder.mHeight;
+ mUseIdentityTransform = builder.mUseIdentityTransform;
+ mRotation = builder.mRotation;
+ }
+
+ /**
+ * The Builder class used to construct {@link DisplayCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private IBinder mDisplayToken;
+ private int mWidth;
+ private int mHeight;
+ private boolean mUseIdentityTransform;
+ private @Surface.Rotation int mRotation = Surface.ROTATION_0;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public DisplayCaptureArgs build() {
+ if (mDisplayToken == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null display token");
+ }
+ return new DisplayCaptureArgs(this);
+ }
+
+ public Builder(IBinder displayToken) {
+ setDisplayToken(displayToken);
+ }
+
+ /**
+ * The display to take the screenshot of.
+ */
+ public Builder setDisplayToken(IBinder displayToken) {
+ mDisplayToken = displayToken;
+ return this;
+ }
+
+ /**
+ * Set the desired size of the returned buffer. The raw screen will be scaled down to
+ * this size
+ *
+ * @param width The desired width of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ * @param height The desired height of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ */
+ public Builder setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ return this;
+ }
+
+ /**
+ * Replace whatever transformation (rotation, scaling, translation) the surface
+ * layers are currently using with the identity transformation while taking the
+ * screenshot.
+ */
+ public Builder setUseIdentityTransform(boolean useIdentityTransform) {
+ mUseIdentityTransform = useIdentityTransform;
+ return this;
+ }
+
+ /**
+ * Apply a custom clockwise rotation to the screenshot, i.e.
+ * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take screenshots in its
+ * native portrait orientation by default, so this is useful for returning screenshots
+ * that are independent of device orientation.
+ */
+ public Builder setRotation(@Surface.Rotation int rotation) {
+ mRotation = rotation;
+ return this;
+ }
+
+ @Override
+ public Builder getThis() {
+ return this;
+ }
+ }
+ }
+
+ /**
+ * The arguments class used to make layer capture requests.
+ *
+ * @see #nativeCaptureLayers(IBinder, long, Rect, float, long[], int)
+ * @hide
+ */
+ public static class LayerCaptureArgs extends CaptureArgs {
+ private final long mNativeLayer;
+ private final long[] mNativeExcludeLayers;
+ private final boolean mChildrenOnly;
+
+ private LayerCaptureArgs(Builder builder) {
+ super(builder);
+ mChildrenOnly = builder.mChildrenOnly;
+ mNativeLayer = builder.mLayer.mNativeObject;
+ mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+ for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+ mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+ }
+ }
+
+ /**
+ * The Builder class used to construct {@link LayerCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private SurfaceControl mLayer;
+ private SurfaceControl[] mExcludeLayers;
+ private boolean mChildrenOnly = true;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public LayerCaptureArgs build() {
+ if (mLayer == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null layer");
+ }
+ return new LayerCaptureArgs(this);
+ }
+
+ public Builder(SurfaceControl layer) {
+ setLayer(layer);
+ }
+
+ /**
+ * The root layer to capture.
+ */
+ public Builder setLayer(SurfaceControl layer) {
+ mLayer = layer;
+ return this;
+ }
+
+
+ /**
+ * An array of layer handles to exclude.
+ */
+ public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
+ mExcludeLayers = excludeLayers;
+ return this;
+ }
+
+ /**
+ * Whether to include the layer itself in the screenshot or just the children and their
+ * descendants.
+ */
+ public Builder setChildrenOnly(boolean childrenOnly) {
+ mChildrenOnly = childrenOnly;
+ return this;
+ }
+
+ @Override
+ public Builder getThis() {
+ return this;
+ }
+
+ }
+ }
+
+ /**
* Builder class for {@link SurfaceControl} objects.
*
* By default the surface will be hidden, and have "unset" bounds, meaning it can
@@ -1969,37 +2219,6 @@
}
/**
- * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
- * @hide
- */
- public static void screenshot(IBinder display, Surface consumer) {
- screenshot(display, consumer, new Rect(), 0, 0, false, 0);
- }
-
- /**
- * Copy the current screen contents into the provided {@link Surface}
- *
- * @param consumer The {@link Surface} to take the screenshot into.
- * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
- * @hide
- */
- public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
- int height, boolean useIdentityTransform, int rotation) {
- if (consumer == null) {
- throw new IllegalArgumentException("consumer must not be null");
- }
-
- final ScreenshotHardwareBuffer buffer = screenshotToBuffer(display, sourceCrop, width,
- height, useIdentityTransform, rotation);
- try {
- consumer.attachAndQueueBufferWithColorSpace(buffer.getHardwareBuffer(),
- buffer.getColorSpace());
- } catch (RuntimeException e) {
- Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
- }
- }
-
- /**
* @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
* @hide
*/
@@ -2014,8 +2233,7 @@
* a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
*
* CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use
- * unless absolutely necessary; prefer the versions that use a {@link Surface} such as
- * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link HardwareBuffer} such as
+ * unless absolutely necessary; prefer the versions that use a {@link HardwareBuffer} such as
* {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
*
* @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e951156..0818abe 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -43,6 +43,7 @@
import android.annotation.Size;
import android.annotation.StyleRes;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.annotation.UiThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AutofillOptions;
@@ -952,8 +953,7 @@
/**
* Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow.
- * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface
- * instead.
+ * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead.
*/
private static boolean sAcceptZeroSizeDragShadow;
@@ -4910,6 +4910,7 @@
*/
@ViewDebug.ExportedProperty(deepExport = true)
@UnsupportedAppUsage
+ @UiContext
protected Context mContext;
@UnsupportedAppUsage
@@ -15071,6 +15072,7 @@
* @return The view's Context.
*/
@ViewDebug.CapturedViewProperty
+ @UiContext
public final Context getContext() {
return mContext;
}
@@ -30023,7 +30025,7 @@
/**
* Dump all private flags in readable format, useful for documentation and
- * sanity checking.
+ * consistency checking.
*/
private static void dumpFlags() {
final HashMap<String, String> found = Maps.newHashMap();
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index ffeeb80..ccf1fb0 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -20,6 +20,7 @@
import android.annotation.FloatRange;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.app.Activity;
import android.app.AppGlobals;
import android.compat.annotation.UnsupportedAppUsage;
@@ -391,7 +392,7 @@
* @see #get(android.content.Context)
* @see android.util.DisplayMetrics
*/
- private ViewConfiguration(Context context) {
+ private ViewConfiguration(@UiContext Context context) {
mConstructedWithContext = true;
final Resources res = context.getResources();
final DisplayMetrics metrics = res.getDisplayMetrics();
@@ -498,7 +499,8 @@
* be {@link Activity} or other {@link Context} created with
* {@link Context#createWindowContext(int, Bundle)}.
*/
- public static ViewConfiguration get(Context context) {
+
+ public static ViewConfiguration get(@UiContext Context context) {
if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
final String errorMessage = "Tried to access UI constants from a non-visual Context:"
+ context;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6552e30..64ddb2f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -64,6 +64,7 @@
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
@@ -349,6 +350,7 @@
@GuardedBy("mWindowCallbacks")
final ArrayList<WindowCallbacks> mWindowCallbacks = new ArrayList<>();
@UnsupportedAppUsage
+ @UiContext
public final Context mContext;
@UnsupportedAppUsage
@@ -719,11 +721,11 @@
false /* useSfChoreographer */);
}
- public ViewRootImpl(Context context, Display display, IWindowSession session) {
+ public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
this(context, display, session, false /* useSfChoreographer */);
}
- public ViewRootImpl(Context context, Display display, IWindowSession session,
+ public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
mContext = context;
mWindowSession = session;
@@ -1329,13 +1331,9 @@
final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
|| insets.top != 0 || insets.bottom != 0;
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
- final boolean wideGamut =
- mContext.getResources().getConfiguration().isScreenWideColorGamut()
- && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
-
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
- mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+ updateColorModeIfNeeded(attrs.getColorMode());
updateForceDarkMode();
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
@@ -2648,7 +2646,7 @@
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
final boolean alwaysConsumeSystemBarsChanged =
mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
- final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
+ updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
@@ -2677,10 +2675,6 @@
// hierarchy is measured below.
dispatchApplyInsets = true;
}
- if (colorModeChanged && mAttachInfo.mThreadedRenderer != null) {
- mAttachInfo.mThreadedRenderer.setWideGamut(
- lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
- }
if (surfaceCreated) {
// If we are creating a new surface, then we need to
@@ -2725,7 +2719,7 @@
mAttachInfo.mThreadedRenderer.destroy();
}
} else if ((surfaceReplaced
- || surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
+ || surfaceSizeChanged || windowRelayoutWasForced)
&& mSurfaceHolder == null
&& mAttachInfo.mThreadedRenderer != null
&& mSurface.isValid()) {
@@ -4557,18 +4551,16 @@
}
}
- private boolean hasColorModeChanged(int colorMode) {
+ private void updateColorModeIfNeeded(int colorMode) {
if (mAttachInfo.mThreadedRenderer == null) {
- return false;
+ return;
}
- final boolean isWideGamut = colorMode == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
- if (mAttachInfo.mThreadedRenderer.isWideGamut() == isWideGamut) {
- return false;
+ // TODO: Centralize this sanitization? Why do we let setting bad modes?
+ // Alternatively, can we just let HWUI figure it out? Do we need to care here?
+ if (!mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
+ colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
}
- if (isWideGamut && !mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
- return false;
- }
- return true;
+ mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
}
@Override
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 446e7aa..1dbf37a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -27,6 +27,7 @@
import android.annotation.StyleRes;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UiContext;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -280,6 +281,7 @@
public static final int DECOR_CAPTION_SHADE_DARK = 2;
@UnsupportedAppUsage
+ @UiContext
private final Context mContext;
@UnsupportedAppUsage
@@ -722,7 +724,7 @@
}
- public Window(Context context) {
+ public Window(@UiContext Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
}
@@ -733,6 +735,7 @@
*
* @return Context The Context that was supplied to the constructor.
*/
+ @UiContext
public final Context getContext() {
return mContext;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 1d54d92..7923ff0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -72,6 +72,7 @@
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
@@ -346,6 +347,7 @@
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE,
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION,
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
+ TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}
@@ -473,9 +475,18 @@
*
* Note that this might still be smaller than the size of the physical display if certain areas
* of the display are not available to windows created in this {@link Context}.
+ * <p>
+ * For example, given that there's a device which have a multi-task mode to limit activities
+ * to a half screen. In this case, {@link #getMaximumWindowMetrics()} reports the bounds of
+ * the half screen which the activity is located, while {@link Display#getRealSize(Point)} still
+ * reports the bounds of the whole physical display.
*
- * @see #getMaximumWindowMetrics()
+ * Despite this, {@link #getMaximumWindowMetrics()} and {@link Display#getRealSize(Point)}
+ * reports the same bounds in general.
+ *
+ * @see #getCurrentWindowMetrics()
* @see WindowMetrics
+ * @see Display#getRealSize(Point)
*/
default @NonNull WindowMetrics getMaximumWindowMetrics() {
throw new UnsupportedOperationException();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2fe7c02..27fbfb6 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -25,11 +25,11 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import android.annotation.NonNull;
+import android.annotation.UiContext;
import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Insets;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
@@ -70,6 +70,7 @@
public final class WindowManagerImpl implements WindowManager {
@UnsupportedAppUsage
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
+ @UiContext
@VisibleForTesting
public final Context mContext;
private final Window mParentWindow;
@@ -233,17 +234,16 @@
@Override
public WindowMetrics getMaximumWindowMetrics() {
- final Rect maxBounds = getMaximumBounds();
+ final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
+ final Rect maxBounds = getMaximumBounds(context);
+
return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
}
- private Rect getMaximumBounds() {
- // TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
- // bound after displayArea feature is finished.
- final Display display = mContext.getDisplayNoVerify();
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
- return new Rect(0, 0, displaySize.x, displaySize.y);
+ private static Rect getMaximumBounds(Context context) {
+ synchronized (ResourcesManager.getInstance()) {
+ return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
+ }
}
// TODO(b/150095967): Set window type to LayoutParams
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index 2d05591..2343bf3 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -19,7 +19,7 @@
import android.graphics.Rect;
/**
- * interface to notify the change of the window magnifier bounds and request to change
+ * interface to notify the changes of the window magnification and request to change
* the magnification mode.
*
* @hide
@@ -27,12 +27,13 @@
oneway interface IWindowMagnificationConnectionCallback {
/**
- * Called when the bounds of the window magnifier is changed.
+ * Called when the bounds of the mirrow window is changed.
*
* @param displayId The logical display id.
* @param bounds The window magnifier bounds in screen coordinates.
*/
void onWindowMagnifierBoundsChanged(int displayId, in Rect bounds);
+
/**
* Changes the magnification mode on specified display. It is invoked by System UI when the
* switch button is toggled.
@@ -41,4 +42,12 @@
* @param magnificationMode new magnification mode.
*/
void onChangeMagnificationMode(int displayId, int magnificationMode);
+
+ /**
+ * Called when the magnified bounds is changed.
+ *
+ * @param displayId The logical display id.
+ * @param sourceBounds The magnified bounds in screen coordinates.
+ */
+ void onSourceBoundsChanged(int displayId, in Rect sourceBounds);
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index cce1090..6300320 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -47,6 +47,9 @@
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
private final int mMaxSuggestionCount;
@@ -67,6 +70,9 @@
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
private @NonNull LocaleList mSupportedLocales;
@@ -227,6 +233,9 @@
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
@DataClass.Generated.Member
public int getMaxSuggestionCount() {
@@ -256,6 +265,9 @@
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
@DataClass.Generated.Member
public @NonNull LocaleList getSupportedLocales() {
@@ -458,6 +470,9 @@
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setMaxSuggestionCount(int value) {
@@ -508,6 +523,9 @@
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setSupportedLocales(@NonNull LocaleList value) {
@@ -604,7 +622,7 @@
}
@DataClass.Generated(
- time = 1588109685838L,
+ time = 1595457701315L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
index be833df..b393c67 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
@@ -32,7 +32,18 @@
*/
@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstructor = true)
public final class InlineSuggestionsResponse implements Parcelable {
- private final @NonNull List<InlineSuggestion> mInlineSuggestions;
+ /**
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
+ */
+ @NonNull
+ private final List<InlineSuggestion> mInlineSuggestions;
/**
* Creates a new {@link InlineSuggestionsResponse}, for testing purpose.
@@ -48,7 +59,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -64,6 +75,15 @@
/**
* Creates a new InlineSuggestionsResponse.
*
+ * @param inlineSuggestions
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
* @hide
*/
@DataClass.Generated.Member
@@ -76,6 +96,16 @@
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
+ */
@DataClass.Generated.Member
public @NonNull List<InlineSuggestion> getInlineSuggestions() {
return mInlineSuggestions;
@@ -164,8 +194,8 @@
};
@DataClass.Generated(
- time = 1578972149519L,
- codegenVersion = "1.0.14",
+ time = 1595891876037L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsResponse.java",
inputSignatures = "private final @android.annotation.NonNull java.util.List<android.view.inputmethod.InlineSuggestion> mInlineSuggestions\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(java.util.List<android.view.inputmethod.InlineSuggestion>)\nclass InlineSuggestionsResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
@Deprecated
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 793d940..f6671d8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,7 @@
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
+import android.annotation.DisplayContext;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1193,7 +1194,7 @@
* @hide
*/
@NonNull
- public static InputMethodManager forContext(Context context) {
+ public static InputMethodManager forContext(@DisplayContext Context context) {
final int displayId = context.getDisplayId();
// For better backward compatibility, we always use Looper.getMainLooper() for the default
// display case.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 16e87f8..97e0689 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1514,7 +1514,8 @@
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
- onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
+ // placeholder values, View's implementation does not use these.
+ onScrollChanged(0, 0, 0, 0);
}
/**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 8c0061d..d969a88 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -431,7 +431,8 @@
mSelectedCenterOffset = childLeft + childCenter - galleryCenter;
}
- onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
+ // placeholder values, View's implementation does not use these.
+ onScrollChanged(0, 0, 0, 0);
invalidate();
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index e58f08a..b4379ec 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -505,7 +505,7 @@
public void reset() {
count = 0;
- // by default there is at least one dummy view type
+ // by default there is at least one placeholder view type
viewTypeCount = 1;
hasStableIds = true;
loadingTemplate = null;
@@ -948,7 +948,7 @@
private void updateTemporaryMetaData(IRemoteViewsFactory factory) {
try {
// get the properties/first view (so that we can use it to
- // measure our dummy views)
+ // measure our placeholder views)
boolean hasStableIds = factory.hasStableIds();
int viewTypeCount = factory.getViewTypeCount();
int count = factory.getCount();
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 6ef570c..2eadb56 100755
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1789,7 +1789,7 @@
return createIntent(action, dataUri, extraData, query, actionKey, actionMsg);
} catch (RuntimeException e ) {
int rowNum;
- try { // be really paranoid now
+ try { // be really defensive now
rowNum = c.getPosition();
} catch (RuntimeException e2 ) {
rowNum = -1;
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
index f089f48..df3024e 100644
--- a/core/java/android/widget/TEST_MAPPING
+++ b/core/java/android/widget/TEST_MAPPING
@@ -17,6 +17,45 @@
}
],
"file_patterns": ["Toast\\.java"]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.LoginActivityTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.AutofillValueTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.CheckoutActivityTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
}
]
}
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 9712311..699a7735 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -59,7 +59,7 @@
*/
public class InlineContentView extends ViewGroup {
- private static final String TAG = "InlineContentView";
+ private static final String TAG = "InlineContentView_test2";
private static final boolean DEBUG = false;
diff --git a/core/java/android/widget/inline/TEST_MAPPING b/core/java/android/widget/inline/TEST_MAPPING
new file mode 100644
index 0000000..0baad5c
--- /dev/null
+++ b/core/java/android/widget/inline/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.inline"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 6fdb182..105e05a 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
@@ -29,6 +31,7 @@
import android.os.LocaleList;
import android.os.RemoteException;
import android.provider.Settings;
+import android.sysprop.LocalizationProperties;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -44,6 +47,9 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
public class LocalePicker extends ListFragment {
private static final String TAG = "LocalePicker";
@@ -93,7 +99,38 @@
}
public static String[] getSupportedLocales(Context context) {
- return context.getResources().getStringArray(R.array.supported_locales);
+ String[] allLocales = context.getResources().getStringArray(R.array.supported_locales);
+
+ Predicate<String> localeFilter = getLocaleFilter();
+ if (localeFilter == null) {
+ return allLocales;
+ }
+
+ List<String> result = new ArrayList<>(allLocales.length);
+ for (String locale : allLocales) {
+ if (localeFilter.test(locale)) {
+ result.add(locale);
+ }
+ }
+
+ int localeCount = result.size();
+ return (localeCount == allLocales.length) ? allLocales
+ : result.toArray(new String[localeCount]);
+ }
+
+ @Nullable
+ private static Predicate<String> getLocaleFilter() {
+ try {
+ return LocalizationProperties.locale_filter()
+ .map(filter -> Pattern.compile(filter).asPredicate())
+ .orElse(null);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Failed to read locale filter.", e);
+ } catch (PatternSyntaxException e) {
+ Log.e(TAG, "Bad locale filter format (\"" + e.getPattern() + "\"), skipping.");
+ }
+
+ return null;
}
public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
@@ -266,6 +303,11 @@
*/
@UnsupportedAppUsage
public static void updateLocales(LocaleList locales) {
+ if (locales != null) {
+ locales = removeExcludedLocales(locales);
+ }
+ // Note: the empty list case is covered by Configuration.setLocales().
+
try {
final IActivityManager am = ActivityManager.getService();
final Configuration config = am.getConfiguration();
@@ -282,6 +324,26 @@
}
}
+ @NonNull
+ private static LocaleList removeExcludedLocales(@NonNull LocaleList locales) {
+ Predicate<String> localeFilter = getLocaleFilter();
+ if (localeFilter == null) {
+ return locales;
+ }
+
+ int localeCount = locales.size();
+ ArrayList<Locale> filteredLocales = new ArrayList<>(localeCount);
+ for (int i = 0; i < localeCount; ++i) {
+ Locale locale = locales.get(i);
+ if (localeFilter.test(locale.toString())) {
+ filteredLocales.add(locale);
+ }
+ }
+
+ return (localeCount == filteredLocales.size()) ? locales
+ : new LocaleList(filteredLocales.toArray(new Locale[0]));
+ }
+
/**
* Get the locale list.
*
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 7195b45a..b2852ea 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -437,7 +437,7 @@
mBinding = true;
final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
- | mBindingFlags;
+ | Context.BIND_INCLUDE_CAPABILITIES | mBindingFlags;
final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
mHandler, new UserHandle(mUserId));
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
index 1f816c1..749ff84 100644
--- a/core/java/com/android/internal/os/ChildZygoteInit.java
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -116,7 +116,7 @@
try {
server.registerServerSocketAtAbstractName(socketName);
- // Add the abstract socket to the FD whitelist so that the native zygote code
+ // Add the abstract socket to the FD allow list so that the native zygote code
// can properly detach it after forking.
Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 9283105..afc9432 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1 +1 @@
-per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2989a5e..1ca9250 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -816,9 +816,9 @@
throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-app");
} else if (args.mStartChildZygote) {
throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote");
- } else if (args.mApiBlacklistExemptions != null) {
+ } else if (args.mApiDenylistExemptions != null) {
throw new IllegalArgumentException(
- USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions");
+ USAP_ERROR_PREFIX + "--set-api-denylist-exemptions");
} else if (args.mHiddenApiAccessLogSampleRate != -1) {
throw new IllegalArgumentException(
USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 94c1f71..22082d0 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -192,10 +192,10 @@
boolean mBootCompleted;
/**
- * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
- * when they change, via --set-api-blacklist-exemptions.
+ * Exemptions from API deny-listing. These are sent to the pre-forked zygote at boot time, or
+ * when they change, via --set-api-denylist-exemptions.
*/
- String[] mApiBlacklistExemptions;
+ String[] mApiDenylistExemptions;
/**
* Sampling rate for logging hidden API accesses to the event log. This is sent to the
@@ -416,10 +416,10 @@
expectRuntimeArgs = false;
} else if (arg.equals("--start-child-zygote")) {
mStartChildZygote = true;
- } else if (arg.equals("--set-api-blacklist-exemptions")) {
+ } else if (arg.equals("--set-api-denylist-exemptions")) {
// consume all remaining args; this is a stand-alone command, never included
// with the regular fork command.
- mApiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
+ mApiDenylistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
curArg = args.length;
expectRuntimeArgs = false;
} else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index ec1b05a..5a576ebb 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -185,8 +185,8 @@
return null;
}
- if (parsedArgs.mApiBlacklistExemptions != null) {
- return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
+ if (parsedArgs.mApiDenylistExemptions != null) {
+ return handleApiDenylistExemptions(zygoteServer, parsedArgs.mApiDenylistExemptions);
}
if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
@@ -367,11 +367,11 @@
}
/**
- * Makes the necessary changes to implement a new API blacklist exemption policy, and then
+ * Makes the necessary changes to implement a new API deny list exemption policy, and then
* responds to the system server, letting it know that the task has been completed.
*
* This necessitates a change to the internal state of the Zygote. As such, if the USAP
- * pool is enabled all existing USAPs have an incorrect API blacklist exemption list. To
+ * pool is enabled all existing USAPs have an incorrect API deny list exemption list. To
* properly handle this request the pool must be emptied and refilled. This process can return
* a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
*
@@ -380,9 +380,9 @@
* @return A Runnable object representing a new app in any USAPs spawned from here; the
* zygote process will always receive a null value from this function.
*/
- private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
+ private Runnable handleApiDenylistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
return stateChangeWithUsapPoolReset(zygoteServer,
- () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
+ () -> ZygoteInit.setApiDenylistExemptions(exemptions));
}
private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5fd9333..32e7fdc 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,10 @@
VMRuntime.registerAppInfo(profilePath, codePaths);
}
- public static void setApiBlacklistExemptions(String[] exemptions) {
+ /**
+ * Sets the list of classes/methods for the hidden API
+ */
+ public static void setApiDenylistExemptions(String[] exemptions) {
VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index a0b50df..bb17337 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -451,7 +451,7 @@
* For reasons of correctness the USAP pool pipe and event FDs
* must be processed before the session and server sockets. This
* is to ensure that the USAP pool accounting information is
- * accurate when handling other requests like API blacklist
+ * accurate when handling other requests like API deny list
* exemptions.
*/
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 0e703fa..205c5fd 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -103,8 +103,11 @@
final DisplayMetrics dm = userRes.getDisplayMetrics();
final float defaultInset = userRes.getDimension(
com.android.internal.R.dimen.config_backGestureInset) / dm.density;
- final float backGestureInset = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
- BACK_GESTURE_EDGE_WIDTH, defaultInset);
+ // Only apply the back gesture config if there is an existing inset
+ final float backGestureInset = defaultInset > 0
+ ? DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+ BACK_GESTURE_EDGE_WIDTH, defaultInset)
+ : defaultInset;
final float inset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, backGestureInset,
dm);
final float scale = Settings.Secure.getFloatForUser(
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 0a3fe09..053b06f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -35,6 +35,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.SearchManager;
@@ -342,7 +343,7 @@
static final RotationWatcher sRotationWatcher = new RotationWatcher();
@UnsupportedAppUsage
- public PhoneWindow(Context context) {
+ public PhoneWindow(@UiContext Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
@@ -352,7 +353,7 @@
/**
* Constructor for main window of an activity.
*/
- public PhoneWindow(Context context, Window preservedWindow,
+ public PhoneWindow(@UiContext Context context, Window preservedWindow,
ActivityConfigCallback activityConfigCallback) {
this(context);
// Only main activity windows use decor context, all the other windows depend on whatever
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c6a1153..6b754ca 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.ArrayUtils.appendInt;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
@@ -245,6 +246,14 @@
*/
private Map<String, Map<String, String>> mNamedActors = null;
+ // Package name of the package pre-installed on a read-only
+ // partition that is used to verify if an overlay package fulfills
+ // the 'config_signature' policy by comparing their signatures:
+ // if the overlay package is signed with the same certificate as
+ // the package declared in 'config-signature' tag, then the
+ // overlay package fulfills the 'config_signature' policy.
+ private String mOverlayConfigSignaturePackage;
+
public static SystemConfig getInstance() {
if (!isSystemProcess()) {
Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
@@ -432,6 +441,12 @@
return mNamedActors != null ? mNamedActors : Collections.emptyMap();
}
+ @Nullable
+ public String getOverlayConfigSignaturePackage() {
+ return TextUtils.isEmpty(mOverlayConfigSignaturePackage)
+ ? null : mOverlayConfigSignaturePackage;
+ }
+
/**
* Only use for testing. Do NOT use in production code.
* @param readPermissions false to create an empty SystemConfig; true to read the permissions.
@@ -1137,6 +1152,27 @@
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "overlay-config-signature": {
+ if (allowAll) {
+ String pkgName = parser.getAttributeValue(null, "package");
+ if (pkgName == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) {
+ mOverlayConfigSignaturePackage = pkgName.intern();
+ } else {
+ throw new IllegalStateException("Reference signature package "
+ + "defined as both "
+ + mOverlayConfigSignaturePackage
+ + " and " + pkgName);
+ }
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
case "rollback-whitelisted-app": {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index d7d8621..7d80993 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -17,4 +17,4 @@
per-file android_view_PointerIcon.* = michaelwr@google.com, svv@google.com
# Zygote
-per-file com_android_internal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
+per-file com_android_internal_os_Zygote.*,fd_utils.* = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 350f358..ff73c74 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -61,8 +61,8 @@
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
- mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos));
+ mInfo.dispatchingTimeoutNanos =
+ env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
jobject tokenObj = env->GetObjectField(obj,
gInputApplicationHandleClassInfo.token);
@@ -77,32 +77,28 @@
return mInfo.token.get() != nullptr;
}
-
// --- Global functions ---
-sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
+std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
JNIEnv* env, jobject inputApplicationHandleObj) {
if (!inputApplicationHandleObj) {
return NULL;
}
AutoMutex _l(gHandleMutex);
-
jlong ptr = env->GetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr);
- NativeInputApplicationHandle* handle;
+ std::shared_ptr<NativeInputApplicationHandle>* handle;
if (ptr) {
- handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+ handle = reinterpret_cast<std::shared_ptr<NativeInputApplicationHandle>*>(ptr);
} else {
jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
- handle = new NativeInputApplicationHandle(objWeak);
- handle->incStrong((void*)android_view_InputApplicationHandle_getHandle);
+ handle = new std::shared_ptr(std::make_shared<NativeInputApplicationHandle>(objWeak));
env->SetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
reinterpret_cast<jlong>(handle));
}
- return handle;
+ return *handle;
}
-
// --- JNI ---
static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
@@ -112,8 +108,9 @@
if (ptr) {
env->SetLongField(obj, gInputApplicationHandleClassInfo.ptr, 0);
- NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
- handle->decStrong((void*)android_view_InputApplicationHandle_getHandle);
+ std::shared_ptr<NativeInputApplicationHandle>* handle =
+ reinterpret_cast<std::shared_ptr<NativeInputApplicationHandle>*>(ptr);
+ delete handle;
}
}
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h
index 52ab3e6..ec99d6d 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.h
+++ b/core/jni/android_hardware_input_InputApplicationHandle.h
@@ -39,8 +39,7 @@
jweak mObjWeak;
};
-
-extern sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
+extern std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
JNIEnv* env, jobject inputApplicationHandleObj);
} // namespace android
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index bdb4544..796c5c4 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -168,8 +168,8 @@
jobject inputApplicationHandleObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputApplicationHandle);
if (inputApplicationHandleObj) {
- sp<InputApplicationHandle> inputApplicationHandle =
- android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+ std::shared_ptr<InputApplicationHandle> inputApplicationHandle =
+ android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
if (inputApplicationHandle != nullptr) {
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *(inputApplicationHandle->getInfo());
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 097af76..5b22e31 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2693,4 +2693,9 @@
// CATEGORY: SETTINGS
// OS: R QPR
SETTINGS_SWIPE_BOTTOM_TO_NOTIFICATION = 1846;
+
+ // OPEN: Settings > System > Gestures > Emergency SOS Gesture
+ // CATEGORY: SETTINGS
+ // OS: S
+ EMERGENCY_SOS_GESTURE_SETTINGS = 1847;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index ac143ac..e4a142b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -445,14 +445,14 @@
// i.e. <pkg1>,<pkg2>,...,<pkgN>
optional SettingProto game_driver_opt_out_apps = 10;
// Game Driver - List of Apps that are forbidden to use Game Driver
- optional SettingProto game_driver_blacklist = 11;
+ optional SettingProto game_driver_denylist = 11;
// Game Driver - List of Apps that are allowed to use Game Driver
- optional SettingProto game_driver_whitelist = 12;
+ optional SettingProto game_driver_allowlist = 12;
// ANGLE - List of Apps that can check ANGLE rules
- optional SettingProto angle_whitelist = 13;
- // Game Driver - List of blacklists, each blacklist is a blacklist for
+ optional SettingProto angle_allowlist = 13;
+ // Game Driver - List of denylists, each denylist is a denylist for
// a specific Game Driver version
- optional SettingProto game_driver_blacklists = 14;
+ optional SettingProto game_driver_denylists = 14;
// ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG
optional SettingProto show_angle_in_use_dialog = 15;
// Game Driver - List of libraries in sphal accessible by Game Driver
diff --git a/core/proto/android/server/alarm/alarmmanagerservice.proto b/core/proto/android/server/alarm/alarmmanagerservice.proto
index b74991d..e1240245 100644
--- a/core/proto/android/server/alarm/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarm/alarmmanagerservice.proto
@@ -59,9 +59,10 @@
// Time since the last wakeup was set.
optional int64 time_since_last_wakeup_set_ms = 15;
optional int64 time_change_event_count = 16;
- // The current set of user whitelisted apps for device idle mode, meaning
+ // The current set of user exempted apps for device idle mode, meaning
// these are allowed to freely schedule alarms. These are app IDs, not UIDs.
- repeated int32 device_idle_user_whitelist_app_ids = 17;
+ // This field is currently unused.
+ repeated int32 device_idle_user_exempt_app_ids = 17;
repeated AlarmClockMetadataProto next_alarm_clock_metadata = 18;
diff --git a/core/proto/android/server/appstatetracker.proto b/core/proto/android/server/appstatetracker.proto
index 51e8845..f5583d4 100644
--- a/core/proto/android/server/appstatetracker.proto
+++ b/core/proto/android/server/appstatetracker.proto
@@ -41,14 +41,14 @@
// UIDs currently in the foreground.
repeated int32 foreground_uids = 11;
- // App ids that are in power-save whitelist.
- repeated int32 power_save_whitelist_app_ids = 3;
+ // App ids that are in power-save exemption list.
+ repeated int32 power_save_exempt_app_ids = 3;
- // App ids that are in power-save user whitelist.
- repeated int32 power_save_user_whitelist_app_ids = 12;
+ // App ids that are in power-save user exemption list.
+ repeated int32 power_save_user_exempt_app_ids = 12;
- // App ids that are in temporary power-save whitelist.
- repeated int32 temp_power_save_whitelist_app_ids = 4;
+ // App ids that are in temporary power-save exemption list.
+ repeated int32 temp_power_save_exempt_app_ids = 4;
message RunAnyInBackgroundRestrictedPackages {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -79,5 +79,5 @@
}
// Packages that are in the EXEMPT bucket.
- repeated ExemptedPackage exempted_packages = 10;
+ repeated ExemptedPackage exempted_bucket_packages = 10;
}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c216638..ff0ba8d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -204,6 +204,7 @@
optional WindowContainerProto window_container = 1;
optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
repeated DisplayAreaChildProto children = 3 [deprecated=true];
+ optional bool is_task_display_area = 4;
}
/* represents a generic child of a DisplayArea */
@@ -275,7 +276,7 @@
optional bool adjusted_for_ime = 23;
optional float adjust_ime_amount = 24;
optional float adjust_divider_amount = 25;
- optional bool animating_bounds = 26;
+ optional bool animating_bounds = 26 [deprecated = true];
optional float minimize_amount = 27;
optional bool created_by_organizer = 28;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bae3bf90..fe290f3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -355,7 +355,6 @@
<protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER" />
<protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER" />
<protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED" />
- <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_CLICKED" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" />
<protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" />
diff --git a/core/res/res/drawable-car-night/car_dialog_button_background.xml b/core/res/res/drawable-car-night/car_dialog_button_background.xml
deleted file mode 100644
index 138cb38..0000000
--- a/core/res/res/drawable-car-night/car_dialog_button_background.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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.
- -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true">
- <ripple android:color="#2371cd">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
- </item>
- </ripple>
- </item>
- <item>
- <ripple android:color="?android:attr/colorControlHighlight">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
- </item>
- </ripple>
- </item>
-</selector>
diff --git a/core/res/res/drawable-car/car_dialog_button_background.xml b/core/res/res/drawable-car/car_dialog_button_background.xml
index a7d40bcd..72e5af3 100644
--- a/core/res/res/drawable-car/car_dialog_button_background.xml
+++ b/core/res/res/drawable-car/car_dialog_button_background.xml
@@ -16,11 +16,18 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
- <ripple android:color="#4b9eff">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
+ <layer-list>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="#3D94CBFF"/>
+ </shape>
</item>
- </ripple>
+ <item>
+ <shape android:shape="rectangle">
+ <stroke android:width="8dp" android:color="#94CBFF"/>
+ </shape>
+ </item>
+ </layer-list>
</item>
<item>
<ripple android:color="?android:attr/colorControlHighlight">
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 03c682f..f5facea 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk kieslys om oop te sluit of maak noodoproep."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk kieslys om oop te maak."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teken patroon om te ontsluit"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Noodoproep"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Keer terug na oproep"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Reg!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probeer weer"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f80da89..b118368 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ለመክፈት ምናሌ ተጫን"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ለመክፈት ስርዓተ ጥለት ሳል"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"የአደጋ ጊዜ ጥሪ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ወደ ጥሪ ተመለስ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ትክክል!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"እንደገና ሞክር"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 41e3e26..26dac61 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -844,8 +844,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"اضغط على \"القائمة\" لإلغاء التأمين أو إجراء اتصال بالطوارئ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"اضغط على \"القائمة\" لإلغاء التأمين."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"رسم نقش لإلغاء التأمين"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"مكالمة طوارئ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"العودة إلى الاتصال"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحيح!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"أعد المحاولة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index c6c8bb5..d0ed635 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক কৰিবলৈ মেনু টিপক।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক কৰিবলৈ আর্হি আঁকক"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"জৰুৰীকালীন কল"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"কললৈ উভতি যাওক"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"শুদ্ধ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আকৌ চেষ্টা কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index f0ff883..c721bbf 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Təcili zəng kilidini açmaq və ya yerləşdirmək üçün Menyu düyməsinə basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmaq üçün Menyu düyməsinə basın."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilidi açmaq üçün model çəkin"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Təcili zəng"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zəngə qayıt"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Düzdür!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bir də cəhd edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8319da7..93ddbe5 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite „Meni“ za otključavanje."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Unesite šablon za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazad na poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tačno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probajte ponovo"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3540516..cff1218 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -568,7 +568,7 @@
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Аўтэнтыфікацыя па адбітках пальцаў скасавана карыстальнікам."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
<string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Занадта шмат спроб. Сканер адбіткаў пальцаў выключаны."</string>
- <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паспрабуйце яшчэ раз."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паўтарыце спробу."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string>
@@ -838,11 +838,10 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Націсніце \"Меню\", каб разблакаваць."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намалюйце камбінацыю разблакоўкі, каб разблакаваць"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Экстранны выклік"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вярнуцца да выкліку"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правільна!"</string>
- <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Паспрабуйце яшчэ раз"</string>
+ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Паўтарыце спробу"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Паўтарыце спробу"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Разблакіраваць для ўсіх функцый і даных"</string>
<string name="faceunlock_multiple_failures" msgid="681991538434031708">"Перавышана максімальная колькасць спроб разблакоўкі праз Фэйскантроль"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6643bcf..e49ae26 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натиснете „Меню“, за да отключите или да извършите спешно обаждане."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натиснете „Меню“, за да отключите."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Нарисувайте фигура, за да отключите"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Спешно обаждане"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад към обаждането"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правилно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Опитайте отново"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index cbec4ac..ffc9ecf 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক করতে বা জরুরি কল করতে মেনু টিপুন৷"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক করতে মেনু টিপুন৷"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক করতে প্যাটার্ন আঁকুন"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"জরুরি কল"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"কলে ফিরুন"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"সঠিক!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আবার চেষ্টা করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 87b02f5..0e176b5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite dugme Meni kako biste otključali uređaj ili obavili hitni poziv."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite dugme Meni za otključavanje uređaja."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nacrtajte uzorak za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Povratak na poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5fadc92..2e4169e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -543,7 +543,7 @@
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No s\'ha reconegut"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"S\'ha cancel·lat l\'autenticació"</string>
- <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha establert cap PIN, patró o contrasenya"</string>
+ <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha definit cap PIN, patró o contrasenya"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error en l\'autenticació"</string>
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
@@ -832,7 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Premeu Menú per desbloquejar-lo o per fer una trucada d\'emergència."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Premeu Menú per desbloquejar."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibuixeu el patró de desbloqueig"</string>
- <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergència"</string>
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Trucada d\'emergència"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Torna a la trucada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcte!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Torna-ho a provar"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c69ca37d..34e6efb 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefon odemknete stisknutím tlačítka Menu."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odblokujte pomocí gesta"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Tísňové volání"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolat zpět"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správně!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zkusit znovu"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index fb10077..117fecb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryk på Menu for at låse op."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn oplåsningsmønster"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nødopkald"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbage til opkald"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rigtigt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv igen"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4adcf0a..faa78df 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Zum Entsperren die Menütaste drücken"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Muster zum Entsperren zeichnen"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Notruf"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zurück zum Anruf"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Erneut versuchen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 23895f4..2e1b56a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Κλήση έκτακτης ανάγκης"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Επιστροφή στην κλήση"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Σωστό!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Προσπαθήστε ξανά"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0484ccd..dcfbf5a 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9981c12..65f2426 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 02cdf69a..d38e2fe 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 3b18aca..30a9bf88 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7e8a89a..27ff3f0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Presionar Menú para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar el patrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Llamada de emergencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regresar a llamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 02aafa7..67350cb0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar patrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Llamada de emergencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver a llamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8136294..3929ed4 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Vajutage avamiseks või hädaabikõne tegemiseks menüünuppu"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Vajutage avamiseks menüüklahvi."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Avamiseks joonistage muster"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hädaabikõne"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kõne juurde tagasi"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Õige."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Proovige uuesti"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 1b88f27..ecce980 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -350,11 +350,11 @@
<string name="permlab_receiveMms" msgid="4000650116674380275">"jaso testu-mezuak (MMSak)"</string>
<string name="permdesc_receiveMms" msgid="958102423732219710">"MMS mezuak jasotzeko eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailura bidalitako mezuak kontrola eta ezaba ditzake zuri erakutsi gabe."</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"desbideratu sare mugikor bidezko igorpen-mezuak"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko igorpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko igorpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko igorpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-igorpenak jasotzean, aplikazio maltzurrek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko igorpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko igorpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko igorpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-igorpenak jasotzean, aplikazio gaiztoek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"irakurri sare mugikor bidezko igorpen-mezuak"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Gailuak jasotako sare mugikor bidezko igorpenen mezuak irakurtzeko baimena ematen die aplikazioei. Sare mugikor bidezko igorpen-alertak kokapen batzuetan ematen dira larrialdi-egoeren berri emateko. Aplikazio gaiztoek gailuaren errendimendua edo funtzionamendua oztopa dezakete larrialdi-igorpen horietako bat jasotzen denean."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"irakurri harpidetutako jarioak"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Unean sinkronizatutako jarioei buruzko xehetasunak lortzeko baimena ematen die aplikazioei."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Une horretan sinkronizatutako jarioei buruzko xehetasunak lortzeko baimena ematen die aplikazioei."</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"bidali eta ikusi SMS mezuak"</string>
<string name="permdesc_sendSms" msgid="6757089798435130769">"SMS mezuak bidaltzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko mezuak bidalita gastuak eragiteko."</string>
<string name="permlab_readSms" msgid="5164176626258800297">"irakurri testu-mezuak (SMSak edo MMSak)"</string>
@@ -364,7 +364,7 @@
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"jaso testu-mezuak (WAP bidezkoak)"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP mezuak jasotzeko eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioak, besteak beste, gailura bidalitako mezuak kontrola eta ezaba ditzake zuri erakutsi gabe."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"eskuratu abian diren aplikazioak"</string>
- <string name="permdesc_getTasks" msgid="7388138607018233726">"Unean edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string>
+ <string name="permdesc_getTasks" msgid="7388138607018233726">"Une honetan edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"kudeatu profilen eta gailuen jabeak"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"Profilaren eta gailuaren jabeak zehazteko baimena ematen die aplikazioei."</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"ordenatu abian diren aplikazioak"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Desblokeatzeko edo larrialdi-deia egiteko, sakatu Menua."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Desblokeatzeko, sakatu Menua."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desblokeatzeko, marraztu eredua"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Larrialdi-deia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Itzuli deira"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Eredua zuzena da!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Saiatu berriro"</string>
@@ -882,7 +881,7 @@
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Pasahitza"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Hasi saioa"</string>
<string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Erabiltzaile-izen edo pasahitz baliogabea."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nZoaz "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nJoan "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Egiaztatzen…"</string>
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"Desblokeatu"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Soinua aktibatuta"</string>
@@ -1604,7 +1603,7 @@
<string name="kg_login_password_hint" msgid="3330530727273164402">"Pasahitza"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"Hasi saioa"</string>
<string name="kg_login_invalid_input" msgid="8292367491901220210">"Erabiltzaile-izen edo pasahitz baliogabea."</string>
- <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nZoaz "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
+ <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nJoan "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
<string name="kg_login_checking_password" msgid="4676010303243317253">"Kontua egiaztatzen…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 506a7ee..1ee4be5 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -829,11 +829,10 @@
<string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"شماره اضطراری"</string>
<string name="lockscreen_carrier_default" msgid="6192313772955399160">"بدون سرویس"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"صفحه قفل شد."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"برای بازگشایی قفل یا انجام تماس اضطراری روی منو فشار دهید."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"برای بازکردن قفل یا انجام تماس اضطراری روی «منو» فشار دهید."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"برای بازگشایی قفل روی منو فشار دهید."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"الگو را بکشید تا قفل آن باز شود"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"تماس اضطراری"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"بازگشت به تماس"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح است!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوباره امتحان کنید"</string>
@@ -1927,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"تنظیم زمان"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"زمان معتبری وارد کنید"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"زمان را تایپ کنید"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"برای وارد کردن زمان، به حالت وارد کردن نوشتار تغییر وضعیت دهید."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"برای وارد کردن زمان، به حالت ورودی نوشتاری تغییر وضعیت دهید."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"برای وارد کردن زمان، به حالت ساعت تغییر وضعیت دهید."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"گزینههای تکمیل خودکار"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"ذخیره کردن برای تکمیل خودکار"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 01db781..1eff983 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Poista lukitus tai soita hätäpuhelu painamalla Valikko-painiketta."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Poista lukitus painamalla Valikko-painiketta."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Poista lukitus piirtämällä kuvio"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hätäpuhelu"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Palaa puheluun"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Oikein!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Yritä uudelleen"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index f5adc77..c6f347b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Appel d\'urgence"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"C\'est exact!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Réessayer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8880dc6..6307c35 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Appel d\'urgence"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Combinaison correcte !"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Veuillez réessayer."</string>
@@ -1938,7 +1937,7 @@
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> suggestions de saisie automatique</item>
</plurals>
<string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
- <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
+ <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer la <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_3types" msgid="6598228952100102578">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ?"</string>
<string name="autofill_update_title" msgid="3630695947047069136">"Mettre à jour cet élément dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index dffca1c..b3a4542 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Preme Menú para desbloquear ou realizar unha chamada de emerxencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Preme Menú para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Crea o padrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emerxencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver á chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Téntao de novo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 784e85f..ca35a68 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"અનલૉક કરવા માટે અથવા કટોકટીનો કૉલ કરવા માટે મેનૂ દબાવો."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"અનલૉક કરવા માટે પૅટર્ન દોરો."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ઇમર્જન્સી કૉલ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"કૉલ પર પાછા ફરો"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"સાચું!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ફરી પ્રયાસ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 82a1062..7b0bd23 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"लॉक खोलने के लिए मेन्यू दबाएं या आपातलकालीन कॉल करें."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करने के लिए आकार आरेखित करें"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आपातकालीन कॉल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉल पर वापस लौटें"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से कोशिश करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f1bcd39..eb41c9f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite Izbornik za otključavanje ili pozivanje hitnih službi."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite Izbornik za otključavanje."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iscrtajte uzorak za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Uzvrati poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3106371..0004ff1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"A feloldáshoz nyomja meg a Menü gombot."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rajzolja le a mintát a feloldáshoz"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Segélyhívás"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Hívás folytatása"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Helyes!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Próbálja újra"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 85afc27..b115025 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Հավաքեք սխեման` ապակողպելու համար"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Շտապ կանչ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Վերադառնալ զանգին"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ճիշտ է:"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Կրկին փորձեք"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 8ec1f50..688996d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk membuka atau melakukan panggilan darurat."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Buat pola untuk membuka"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Panggilan darurat"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Perbaiki!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Coba lagi"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 1b0c2fe..899fa52 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ýttu á valmyndartakkann til að taka úr lás eða hringja neyðarsímtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ýttu á valmyndartakkann til að taka úr lás."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teiknaðu mynstur til að taka úr lás"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Neyðarsímtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Aftur í símtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rétt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Reyndu aftur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d2bf62d..400c44a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Premi Menu per sbloccare."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Traccia la sequenza di sblocco"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chiamata di emergenza"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Torna a chiamata"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corretta."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Riprova"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 4d6d8155..2c42745 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -838,7 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"לחץ על \'תפריט\' כדי לבטל את הנעילה או כדי לבצע שיחת חירום."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"שרטט קו לביטול נעילת המסך"</string>
- <string name="lockscreen_emergency_call" msgid="7500692654885445299">"חירום"</string>
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"שיחת חירום"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"חזרה לשיחה"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"נכון!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"כדאי לנסות שוב"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f9674bd..fdb505b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"MENUキーでロック解除(または緊急通報)"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"MENUキーでロック解除"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"パターンを入力"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急通報"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"通話に戻る"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"一致しました"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"もう一度お試しください"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3d1e9c7..3d0d88b 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"განბლოკვისთვის ან გადაუდებელი ზარისთვის დააჭირეთ მენიუს."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"განსაბლოკად დახატეთ ნიმუში"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"გადაუდებელი ზარი"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ზარზე დაბრუნება"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"სწორია!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"კიდევ სცადეთ"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 38a50ab..6d063b6 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Бекітпесін ашу үшін немесе төтенше қоңырауды табу үшін Мәзір тармағын басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ашу үшін Мәзір пернесін басыңыз."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Бекітпесін ашу үшін кескінді сызыңыз"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Құтқару қызметіне қоңырау шалу"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Қоңырауға оралу"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Дұрыс!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Қайталап көріңіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4e646c5..b9378de 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ចុចម៉ឺនុយ ដើម្បីដោះសោ ឬហៅពេលអាសន្ន។"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"គូរលំនាំ ដើម្បីដោះសោ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ហៅទៅលេខសង្គ្រោះបន្ទាន់"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ត្រឡប់ទៅការហៅ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ត្រឹមត្រូវ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ព្យាយាមម្ដងទៀត"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8d74215..cbb9ca2 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ ಇಲ್ಲವೇ ತುರ್ತು ಕರೆಯನ್ನು ಮಾಡಿ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ತುರ್ತು ಕರೆ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ಕರೆಗೆ ಹಿಂತಿರುಗು"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ಸರಿಯಾಗಿದೆ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5d960dc..78c3286 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"잠금해제하려면 메뉴를 누르세요."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"잠금해제를 위해 패턴 그리기"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"긴급 전화"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"통화로 돌아가기"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"맞습니다."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"다시 시도"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c97324f..671863d 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -47,7 +47,7 @@
<string name="mismatchPin" msgid="2929611853228707473">"Терилген PIN\'дер дал келбейт."</string>
<string name="invalidPin" msgid="7542498253319440408">"Узундугу 4төн 8ге чейинки сандан турган PIN-кодду териңиз."</string>
<string name="invalidPuk" msgid="8831151490931907083">"Узундугу 8 же көбүрөөк сандан турган PUK-кодду териңиз."</string>
- <string name="needPuk" msgid="7321876090152422918">"SIM картаңыз PUK менен кулпуланган. Кулпусун ачуу үчүн PUK-кодду териңиз."</string>
+ <string name="needPuk" msgid="7321876090152422918">"SIM картаңыз PUK менен кулпуланган. Кулпусун ачуу үчүн, PUK-кодду териңиз."</string>
<string name="needPuk2" msgid="7032612093451537186">"SIM картаны бөгөттөн чыгаруу үчүн PUK2 кодун териңиз."</string>
<string name="enablePin" msgid="2543771964137091212">"Оңунан чыкпады, SIM/RUIM бөгөттөөсүн жандырыңыз."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
@@ -241,7 +241,7 @@
<string name="global_action_power_off" msgid="4404936470711393203">"Өчүрүү"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Кубат"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Өчүрүп күйгүзүү"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"Тез жардам"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"Шашылыш чалуу"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Ката тууралуу билдирүү"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Сеансты бүтүрүү"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Скриншот"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Кулпусун ачып же Шашылыш чалуу аткаруу үчүн менюну басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Бөгөттөн чыгаруу үчүн Менюну басыңыз."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Кулпуну ачуу үчүн, үлгүнү тартыңыз"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Шашылыш чалуу"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Чалууга кайтуу"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Туура!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дагы аракет кылыңыз"</string>
@@ -1321,7 +1320,7 @@
<string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string>
<string name="console_running_notification_message" msgid="7892751888125174039">"Майнаптуулугуна таасири тиет. Аны өчүрүү үчүн операциялык тутумду жүктөгүчтү текшериңиз."</string>
<string name="usb_contaminant_detected_title" msgid="4359048603069159678">"USB портунда суюктук же урандылар бар"</string>
- <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB порт автоматтык түрдө өчүрүлдү. Кененирээк маалымат алуу үчүн таптап коюңуз."</string>
+ <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB порт автоматтык түрдө өчүрүлдү. Кененирээк маалымат алуу үчүн, таптап коюңуз."</string>
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB портун колдонууга болот"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"Телефон суюктук менен урандыларды аныктаган жок."</string>
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index c1b3fe4..4451139 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ກົດ ເມນູ ເພື່ອປົດລັອກ ຫຼື ໂທອອກຫາເບີສຸກເສີນ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ແຕ້ມຮູບແບບເພື່ອປົດລັອກ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ການໂທສຸກເສີນ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ກັບໄປຫາການໂທ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ຖືກຕ້ອງ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ລອງໃໝ່ອີກຄັ້ງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fc5709c..fa07978 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Paspauskite „Meniu“, kad atrakintumėte ar skambintumėte pagalbos numeriu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Paspauskite „Meniu“, jei norite atrakinti."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nustatyti modelį, kad atrakintų"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Skambutis pagalbos numeriu"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"grįžti prie skambučio"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Teisingai!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bandykite dar kartą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d780b14..e8107fb 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nospiediet Izvēlne, lai atbloķētu, vai veiciet ārkārtas zvanu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Lai atbloķētu, nospiediet vienumu Izvēlne."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Zīmējiet kombināciju, lai atbloķētu."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Ārkārtas izsaukums"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Atpakaļ pie zvana"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pareizi!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Mēģināt vēlreiz"</string>
@@ -1816,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
- <string name="battery_saver_description" msgid="6794188153647295212">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora enerģijas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora enerģijas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string>
@@ -2034,9 +2033,9 @@
<string name="notification_feedback_indicator" msgid="663476517711323016">"Sniegt atsauksmes"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora jaudas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora jaudas taupīšanas režīms"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora jaudas taupīšanas režīms ir izslēgts"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora enerģijas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora enerģijas taupīšanas režīms"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora enerģijas taupīšanas režīms ir izslēgts"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Tālruņa uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Planšetdatora uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Ierīces uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b50c608..8871293 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисни „Мени“ да се отклучи или да направи итен повик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притиснете „Мени“ за да се отклучи."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Употребете ја шемата за да се отклучи"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Итен повик"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Врати се на повик"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Точно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Обидете се повторно"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b769fd2..af75969 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"അൺലോക്ക് ചെയ്യുന്നതിനായി മെനു അമർത്തുക അല്ലെങ്കിൽ അടിയന്തര കോൾ വിളിക്കുക."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"അൺലോക്ക് ചെയ്യാൻ പാറ്റേൺ വരയ്ക്കുക"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"എമർജൻസി കോൾ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"കോളിലേക്ക് മടങ്ങുക"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ശരി!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"വീണ്ടും ശ്രമിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7b41501..a65f80c 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Яаралтай дуудлага хийх буюу эсвэл түгжээг тайлах бол цэсийг дарна уу."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Тайлах бол цэсийг дарна уу."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Тайлах хээгээ зурна уу"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Яаралтай дуудлага"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Дуудлагаруу буцах"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Зөв!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дахин оролдох"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5778033..ec240c1 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलॉक करण्यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलॉक करण्यासाठी मेनू दाबा."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करण्यासाठी पॅटर्न काढा"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आणीबाणी कॉल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉलवर परत या"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"अचूक!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"पुन्हा प्रयत्न करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c30bcfc..2e78b45 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk menyahsekat atau membuat panggilan kecemasan."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka kunci."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Lukiskan corak untuk membuka kunci"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Panggilan kecemasan"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Betul!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Cuba lagi"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 243357e..1ebafa4 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ဖွင့်ရန်သို့မဟုတ်အရေးပေါ်ခေါ်ဆိုခြင်းပြုလုပ်ရန် မီနူးကိုနှိပ်ပါ"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"မီးနူးကို နှိပ်ခြင်းဖြင့် သော့ဖွင့်ပါ"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ဖွင့်ရန်ပုံစံဆွဲပါ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"အရေးပေါ် ခေါ်ဆိုမှု"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ခေါ်ဆိုမှုထံပြန်သွားရန်"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"မှန်ပါသည်"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ထပ် စမ်းပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0a31b49..ac21aec 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Trykk på menyknappen for å låse opp."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn mønster for å låse opp"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nødanrop"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbake til samtale"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Riktig!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv på nytt"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9712b48..fd7b1b2 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलक वा आपतकालीन कल गर्न मेनु थिच्नुहोस्।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलक गर्न मेनु थिच्नुहोस्।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलक गर्नु ढाँचा खिच्नुहोस्"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आपतकालीन कल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कलमा फर्किनुहोस्"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फेरि प्रयास गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d1a342c..f63e647 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -326,7 +326,7 @@
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Schermvergroting bedienen"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Het zoomniveau en de positionering van het scherm bedienen."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Gebaren uitvoeren"</string>
- <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
+ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tikken, swipen, knijpen en andere gebaren uitvoeren."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Vingerafdrukgebaren"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan gebaren registreren die op de vingerafdruksensor van het apparaat worden getekend."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot maken"</string>
@@ -451,7 +451,7 @@
<string name="permlab_accessImsCallService" msgid="442192920714863782">"toegang tot IMS-service voor bellen"</string>
<string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Hiermee kan de app de IMS-service gebruiken om te bellen zonder je tussenkomst."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"telefoonstatus en -identiteit lezen"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een gesprek actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze rechten kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een gesprek actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"gesprekken doorschakelen via het systeem"</string>
<string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Hiermee kan de app de bijbehorende gesprekken doorschakelen via het systeem om de belfunctionaliteit te verbeteren."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"gesprekken via het systeem bekijken en beheren"</string>
@@ -489,7 +489,7 @@
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"netwerkverbindingen weergeven"</string>
<string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Hiermee kan de app informatie bekijken over netwerkverbindingen, zoals welke netwerken er zijn en welke verbonden zijn."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"volledige netwerktoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Hiermee kan de app netwerksockets maken en aangepaste netwerkprotocollen gebruiken. De browser en andere apps bieden mogelijkheden om gegevens via internet te verzenden, dus deze toestemming is niet vereist om gegevens via internet te verzenden."</string>
+ <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Hiermee kan de app netwerksockets maken en aangepaste netwerkprotocollen gebruiken. De browser en andere apps bieden mogelijkheden om gegevens via internet te verzenden, dus deze rechten zijn niet vereist om gegevens via internet te verzenden."</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"netwerkverbinding wijzigen"</string>
<string name="permdesc_changeNetworkState" msgid="649341947816898736">"Hiermee kan de app de status van de netwerkverbinding wijzigen."</string>
<string name="permlab_changeTetherState" msgid="9079611809931863861">"getetherde verbinding wijzigen"</string>
@@ -569,7 +569,7 @@
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
- <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-pictogram"</string>
+ <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"hardware voor ontgrendelen via gezichtsherkenning beheren"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Hiermee kan de app methoden aanroepen om gezichtstemplates toe te voegen en te verwijderen voor gebruik."</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"hardware voor ontgrendelen via gezichtsherkenning gebruiken"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk op \'Menu\' om te ontgrendelen."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Patroon tekenen om te ontgrendelen"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Noodoproep"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Terug naar gesprek"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Juist!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Opnieuw proberen"</string>
@@ -954,12 +953,12 @@
<string name="autofill_parish" msgid="6847960518334530198">"Gemeente"</string>
<string name="autofill_area" msgid="8289022370678448983">"Gebied"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Emiraat"</string>
- <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbladwijzers en -geschiedenis lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbladwijzers en -geschiedenis schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
+ <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbookmarks en -geschiedenis lezen"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbookmarks en -geschiedenis schrijven"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bookmarks bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"een wekker instellen"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"voicemail toevoegen"</string>
@@ -970,7 +969,7 @@
<string name="save_password_notnow" msgid="2878327088951240061">"Niet nu"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Onthouden"</string>
<string name="save_password_never" msgid="6776808375903410659">"Nooit"</string>
- <string name="open_permission_deny" msgid="5136793905306987251">"Je hebt geen toestemming om deze pagina te openen."</string>
+ <string name="open_permission_deny" msgid="5136793905306987251">"Je hebt geen rechten om deze pagina te openen."</string>
<string name="text_copied" msgid="2531420577879738860">"Tekst naar klembord gekopieerd."</string>
<string name="copied" msgid="4675902854553014676">"Gekopieerd"</string>
<string name="more_item_label" msgid="7419249600215749115">"Meer"</string>
@@ -1398,7 +1397,7 @@
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"verwijdering van pakketten aanvragen"</string>
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Hiermee kan een app verwijdering van pakketten aanvragen."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"vragen om batterijoptimalisatie te negeren"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Hiermee kan een app toestemming vragen om batterijoptimalisatie voor die app te negeren."</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Hiermee kan een app rechten vragen om batterijoptimalisatie voor die app te negeren."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tik twee keer voor zoomregeling"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Kan widget niet toevoegen."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ga"</string>
@@ -1410,13 +1409,13 @@
<string name="ime_action_default" msgid="8265027027659800121">"Uitvoeren"</string>
<string name="dial_number_using" msgid="6060769078933953531">"Nummer bellen\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="6200708808003692594">"Contact maken\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"De volgende apps verzoeken om toegang tot je account, nu en in de toekomst."</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"De volgende apps willen toegangsrechten voor je account, nu en in de toekomst."</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Wil je dit verzoek toestaan?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"Verzoek om toegang"</string>
<string name="allow" msgid="6195617008611933762">"Toestaan"</string>
<string name="deny" msgid="6632259981847676572">"Weigeren"</string>
- <string name="permission_request_notification_title" msgid="1810025922441048273">"Toestemming gevraagd"</string>
- <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Toestemming gevraagd\nvoor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+ <string name="permission_request_notification_title" msgid="1810025922441048273">"Rechten gevraagd"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Rechten gevraagd\nvoor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="4620359037192871015">"Je gebruikt deze app buiten je werkprofiel"</string>
<string name="forward_intent_to_work" msgid="3620262405636021151">"U gebruikt deze app in je werkprofiel"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Invoermethode"</string>
@@ -1502,7 +1501,7 @@
<string name="shareactionprovider_share_with" msgid="2753089758467748982">"Delen met"</string>
<string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Delen met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="982510275422590757">"Schuifgreep. Tikken en blijven aanraken."</string>
- <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Vegen om te ontgrendelen"</string>
+ <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Swipen om te ontgrendelen"</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Navigeren naar startpositie"</string>
<string name="action_bar_up_description" msgid="6611579697195026932">"Omhoog navigeren"</string>
<string name="action_menu_overflow_description" msgid="4579536843510088170">"Meer opties"</string>
@@ -1773,7 +1772,7 @@
</plurals>
<string name="restr_pin_try_later" msgid="5897719962541636727">"Probeer het later opnieuw"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Volledig scherm wordt weergegeven"</string>
- <string name="immersive_cling_description" msgid="7092737175345204832">"Veeg omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
+ <string name="immersive_cling_description" msgid="7092737175345204832">"Swipe omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ik snap het"</string>
<string name="done_label" msgid="7283767013231718521">"Gereed"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ronde schuifregelaar voor uren"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 84815f7..a1fd3f0 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ କିମ୍ବା ଜରୁରୀକାଳୀନ କଲ୍ କରନ୍ତୁ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ଅନଲକ୍ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ଅନଲକ୍ କରିବା ପାଇଁ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ଜରୁରୀକାଳୀନ କଲ୍"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"କଲ୍କୁ ଫେରନ୍ତୁ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ଠିକ୍!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c29308f..903ff83 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ਸੰਕਟਕਾਲੀਨ ਕਾਲ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ਕਾਲ ਤੇ ਵਾਪਸ ਜਾਓ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ਸਹੀ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index df56457..aeebf88 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Naciśnij Menu, aby odblokować."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Narysuj wzór, aby odblokować"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Połączenie alarmowe"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Powrót do połączenia"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Poprawnie!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Spróbuj ponownie."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3ecf28d..aedc047 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index dcc8e17..883e4bf 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Prima Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhar padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regressar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tentar novamente"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3ecf28d..aedc047 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6493668..ebc5827 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Apăsați Meniu pentru deblocare."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenați modelul pentru a debloca"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Apel de urgență"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Reveniți la apel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corect!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Încercați din nou"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 07abf6d..f3d13ce 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Для разблокировки нажмите \"Меню\"."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Введите графический ключ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Экстренный вызов"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вернуться к вызову"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторите попытку"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index d494a36..cc6783a 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"අගුළු හැරීමට මෙනුව ඔබන්න හෝ හදිසි ඇමතුම ලබාගන්න."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"අගුළු හැරීමට මෙනු ඔබන්න."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"අගුළු ඇරීමට රටාව අඳින්න"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"හදිසි ඇමතුම"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ඇමතුම වෙත නැවත යන්න"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"නිවැරදියි!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"නැවත උත්සාහ කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 52c5301..b612565 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ak chcete odomknúť telefón alebo uskutočniť tiesňové volanie, stlačte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefón odomknete stlačením tlačidla Menu."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odomknite nakreslením vzoru"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Tiesňové volanie"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolať späť"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správne!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Skúsiť znova"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a43c900..9f23a76 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Če želite odkleniti napravo ali opraviti klic v sili, pritisnite meni."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Če želite odkleniti, pritisnite meni."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Če želite odkleniti, narišite vzorec"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Klic v sili"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazaj na klic"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pravilno."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Poskusi znova"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 625962f..3e7ca92 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Shtyp \"Meny\" për të shkyçur ose për të kryer telefonatë urgjence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Shtyp \"Meny\" për të shkyçur."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vizato modelin për ta shkyçur"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Telefonata e urgjencës"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kthehu te telefonata"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Saktë!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Provo sërish"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6101dac..a3eb3e4 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притисните „Мени“ за откључавање."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Унесите шаблон за откључавање"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Хитни позив"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад на позив"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Тачно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Пробајте поново"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e30bb14..e144243 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryck på Menu för att låsa upp eller ringa nödsamtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryck på Menu för att låsa upp."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita grafiskt lösenord för att låsa upp"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nödsamtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tillbaka till samtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Försök igen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4e4c0f6..22736d8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Bonyeza Menyu ili kufungua au kupiga simu ya dharura."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Bonyeza Menyu ili kufungua."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Chora ruwaza ili kufungua"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Simu ya dharura"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Rudi kwa kupiga simu"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Sahihi!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Jaribu tena"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index a617248..42b2d9c 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"தடைநீக்க மெனுவை அழுத்தவும் அல்லது அவசர அழைப்பை மேற்கொள்ளவும்."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"திறக்க, மெனுவை அழுத்தவும்."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"திறக்க வடிவத்தை வரையவும்"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"அவசர அழைப்பு"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"அழைப்பிற்குத் திரும்பு"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"சரி!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"மீண்டும் முயற்சிக்கவும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 794fec8..854427b 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"అన్లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెను నొక్కండి."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"అన్లాక్ చేయడానికి మెను నొక్కండి."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"అన్లాక్ చేయడానికి నమూనాను గీయండి"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ఎమర్జెన్సీ కాల్"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"కాల్కు తిరిగి వెళ్లు"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"సరైనది!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"మళ్లీ ప్రయత్నించండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3deb9b2..4b39c63 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"กด เมนู เพื่อปลดล็อกหรือโทรฉุกเฉิน"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"กด เมนู เพื่อปลดล็อก"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"วาดรูปแบบเพื่อปลดล็อก"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"หมายเลขฉุกเฉิน"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"กลับสู่การโทร"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ถูกต้อง!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ลองอีกครั้ง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index ccda1c4..beebbd2 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pindutin ang Menu upang i-unlock o magsagawa ng pang-emergency na tawag."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pindutin ang Menu upang i-unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iguhit ang pattern upang i-unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency na tawag"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Bumalik sa tawag"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tama!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Subukang muli"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 85c6986..17852a6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmak için Menü\'ye basın."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilit açmak için deseni çizin"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Acil durum araması"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Çağrıya dön"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Doğru!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tekrar deneyin"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8ae20a5..31684e0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натис. меню, щоб розбл. чи зробити авар. виклик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натисн. меню, щоб розбл."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намал. ключ, щоб розбл."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Екстрений виклик"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Поверн. до дзвін."</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторіть спробу"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 94c6cd4..ed32b24 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"غیر مقفل کرنے کیلئے مینو دبائیں یا ہنگامی کال کریں۔"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"غیر مقفل کرنے کیلئے پیٹرن کو ڈرا کریں"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ہنگامی کال"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"کال پر واپس جائیں"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوبارہ کوشش کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 74676df..4f19644 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Qulfni ochish uchun \"Menyu\"ga bosing."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Qulfni ochish uchun grafik kalitni chizing"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Favqulodda chaqiruv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Qo‘ng‘iroqni qaytarish"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"To‘g‘ri!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Qaytadan urining"</string>
@@ -902,7 +901,7 @@
<string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"Foydalanuvchi tanlagichi"</string>
<string name="keyguard_accessibility_status" msgid="6792745049712397237">"Holati"</string>
<string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Kamera"</string>
- <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Media boshqaruvlari"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Media boshqaruvi"</string>
<string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"Vidjetlarni saralashni boshlandi."</string>
<string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"Vidjetlarni saralash tugatildi."</string>
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vidjeti o‘chirildi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 48f3858..3cb264d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Nhấn vào Menu để mở khóa."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vẽ hình để mở khóa"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Cuộc gọi khẩn cấp"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Quay lại cuộc gọi"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Chính xác!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Thử lại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index bf381ec..0a241da 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按 Menu 解锁或进行紧急呼救。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按 MENU 解锁。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"绘制解锁图案"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"紧急呼叫"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通话"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正确!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"重试"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a3b20d1..6e584d6 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按選單鍵解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按選單鍵解鎖。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖形以解除鎖定螢幕"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急電話"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f6543c9..ab1a423 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按下 [Menu] 解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按下 Menu 鍵解鎖。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖案"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急電話"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 85f54e9..582d435 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chofoza Menyu ukuvula noma ukwenza ikholi ephuthumayo."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Chofoza Menyu ukuvula."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dweba iphathini ukuvula"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Ikholi ephuthumayo"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Buyela ekholini"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Lungile!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zama futhi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bc4c099..8913e8b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -983,7 +983,7 @@
with the modem or some other restricted hardware, add "/dev/bus/usb/001/"
to this list. If this is empty, no parts of the host USB bus will be excluded.
-->
- <string-array name="config_usbHostBlacklist" translatable="false">
+ <string-array name="config_usbHostDenylist" translatable="false">
</string-array>
<!-- List of paths to serial ports that are available to the serial manager.
@@ -2802,6 +2802,9 @@
eutran : eutranSupportedRelease
nfc : contactlessSupportedRelease
crl : rspCrlSupportedVersion
+ nrepc : nrEpcSupportedRelease
+ nr5gc : nr5gcSupportedRelease
+ eutran5gc : eutran5gcSupportedRelease
-->
<string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
<!-- Example:
@@ -2813,6 +2816,9 @@
<item>"eutran,11"</item>
<item>"nfc,1"</item>
<item>"crl,1"</item>
+ <item>"nrepc,15"</item>
+ <item>"nr5gc,15"</item>
+ <item>"eutran5gc,15"</item>
-->
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 16427cd..d5c72da 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1853,7 +1853,7 @@
<java-symbol type="array" name="config_tether_upstream_types" />
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
- <java-symbol type="array" name="config_usbHostBlacklist" />
+ <java-symbol type="array" name="config_usbHostDenylist" />
<java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
diff --git a/tests/utils/DummyIME/Android.bp b/core/sysprop/Android.bp
similarity index 67%
copy from tests/utils/DummyIME/Android.bp
copy to core/sysprop/Android.bp
index 4a44b3b..7f20a0b 100644
--- a/tests/utils/DummyIME/Android.bp
+++ b/core/sysprop/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2012 The Android Open Source Project
+// 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.
@@ -12,10 +11,11 @@
// 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.
-//
-android_test {
- name: "DummyIME",
- srcs: ["src/**/*.java"],
- sdk_version: "current",
+sysprop_library {
+ name: "com.android.sysprop.localization",
+ srcs: ["LocalizationProperties.sysprop"],
+ property_owner: "Platform",
+ api_packages: ["android.sysprop"],
+ vendor_available: false,
}
diff --git a/core/sysprop/LocalizationProperties.sysprop b/core/sysprop/LocalizationProperties.sysprop
new file mode 100644
index 0000000..65f544f
--- /dev/null
+++ b/core/sysprop/LocalizationProperties.sysprop
@@ -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.
+
+module: "android.sysprop.LocalizationProperties"
+owner: Platform
+
+prop {
+ api_name: "locale_filter"
+ type: String
+ prop_name: "ro.localization.locale_filter"
+ 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
new file mode 100644
index 0000000..fe4f457
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.localization-current.txt
@@ -0,0 +1,9 @@
+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.localization-latest.txt b/core/sysprop/api/com.android.sysprop.localization-latest.txt
new file mode 100644
index 0000000..fe4f457
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.localization-latest.txt
@@ -0,0 +1,9 @@
+props {
+ module: "android.sysprop.LocalizationProperties"
+ prop {
+ api_name: "locale_filter"
+ type: String
+ scope: Internal
+ prop_name: "ro.localization.locale_filter"
+ }
+}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index 1edd962..e42b4b4 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -20,7 +20,11 @@
"android.test.runner",
"android.test.base",
],
- static_libs: ["androidx.test.rules", "truth-prebuilt"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "truth-prebuilt",
+ ],
test_suites: ["general-tests"],
sdk_version: "test_current",
platform_apis: true,
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 1533377..9246a23 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.Manifest;
@@ -25,17 +27,27 @@
import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.StrictMode;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExternalResource;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -51,9 +63,11 @@
@RunWith(JUnit4.class)
public class BugreportManagerTest {
@Rule public TestName name = new TestName();
+ @Rule public ExtendedStrictModeVmPolicy mTemporaryVmPolicy = new ExtendedStrictModeVmPolicy();
private static final String TAG = "BugreportManagerTest";
private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+ private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private Handler mHandler;
private Executor mExecutor;
@@ -86,6 +100,8 @@
@After
public void teardown() throws Exception {
dropPermissions();
+ FileUtils.closeQuietly(mBugreportFd);
+ FileUtils.closeQuietly(mScreenshotFd);
}
@@ -95,47 +111,45 @@
// wifi bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, wifi(),
mExecutor, callback);
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
// Wifi bugreports should not receive any progress.
assertThat(callback.hasReceivedProgress()).isFalse();
- // TODO: Because of b/130234145, consent dialog is not shown; so we get a timeout error.
- // When the bug is fixed, accept consent via UIAutomator and verify contents
- // of mBugreportFd.
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_interactive() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
// interactive bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, interactive(),
mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
// Interactive bugreports show progress updates.
assertThat(callback.hasReceivedProgress()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_full() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
- // bugreport and screenshot files should be empty when user consent timed out.
- assertThat(mBugreportFile.length()).isEqualTo(0);
- assertThat(mScreenshotFile.length()).isEqualTo(0);
+ // bugreport and screenshot files shouldn't be empty when user consents.
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
+ assertThat(mScreenshotFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -144,6 +158,8 @@
// Start bugreport #1
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, wifi(), mExecutor, callback);
+ // TODO(b/162389762) Make sure the wait time is reasonable
+ shareConsentDialog(ConsentReply.ALLOW);
// Before #1 is done, try to start #2.
assertThat(callback.isDone()).isFalse();
@@ -375,4 +391,88 @@
private static BugreportParams full() {
return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL);
}
+
+ /* Allow/deny the consent dialog to sharing bugreport data or check existence only. */
+ private enum ConsentReply {
+ ALLOW,
+ DENY,
+ TIMEOUT
+ }
+
+ /*
+ * Ensure the consent dialog is shown and take action according to <code>consentReply<code/>.
+ * It will fail if the dialog is not shown when <code>ignoreNotFound<code/> is false.
+ */
+ private void shareConsentDialog(@NonNull ConsentReply consentReply) throws Exception {
+ mTemporaryVmPolicy.permitIncorrectContextUse();
+ final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+ // Unlock before finding/clicking an object.
+ device.wakeUp();
+ device.executeShellCommand("wm dismiss-keyguard");
+
+ final BySelector consentTitleObj = By.res("android", "alertTitle");
+ if (!device.wait(Until.hasObject(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)) {
+ fail("The consent dialog is not found");
+ }
+ if (consentReply.equals(ConsentReply.TIMEOUT)) {
+ return;
+ }
+ final BySelector selector;
+ if (consentReply.equals(ConsentReply.ALLOW)) {
+ selector = By.res("android", "button1");
+ Log.d(TAG, "Allow the consent dialog");
+ } else { // ConsentReply.DENY
+ selector = By.res("android", "button2");
+ Log.d(TAG, "Deny the consent dialog");
+ }
+ final UiObject2 btnObj = device.findObject(selector);
+ assertNotNull("The button of consent dialog is not found", btnObj);
+ btnObj.click();
+
+ Log.d(TAG, "Wait for the dialog to be dismissed");
+ assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
+ }
+
+ /**
+ * A rule to change strict mode vm policy temporarily till test method finished.
+ *
+ * To permit the non-visual context usage in tests while taking bugreports need user consent,
+ * or UiAutomator/BugreportManager.DumpstateListener would run into error.
+ * UiDevice#findObject creates UiObject2, its Gesture object and ViewConfiguration and
+ * UiObject2#click need to know bounds. Both of them access to WindowManager internally without
+ * visual context comes from InstrumentationRegistry and violate the policy.
+ * Also <code>DumpstateListener<code/> violate the policy when onScreenshotTaken is called.
+ *
+ * TODO(b/161201609) Remove this class once violations fixed.
+ */
+ static class ExtendedStrictModeVmPolicy extends ExternalResource {
+ private boolean mWasVmPolicyChanged = false;
+ private StrictMode.VmPolicy mOldVmPolicy;
+
+ @Override
+ protected void after() {
+ restoreVmPolicyIfNeeded();
+ }
+
+ public void permitIncorrectContextUse() {
+ // Allow to call multiple times without losing old policy.
+ if (mOldVmPolicy == null) {
+ mOldVmPolicy = StrictMode.getVmPolicy();
+ }
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectAll()
+ .permitIncorrectContextUse()
+ .penaltyLog()
+ .build());
+ mWasVmPolicyChanged = true;
+ }
+
+ private void restoreVmPolicyIfNeeded() {
+ if (mWasVmPolicyChanged && mOldVmPolicy != null) {
+ StrictMode.setVmPolicy(mOldVmPolicy);
+ mOldVmPolicy = null;
+ }
+ }
+ }
}
diff --git a/core/tests/coretests/apks/install/res/values/strings.xml b/core/tests/coretests/apks/install/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install/res/values/strings.xml
+++ b/core/tests/coretests/apks/install/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml b/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml b/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml b/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml b/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml b/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml b/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml b/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml b/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_verifier_bad/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml b/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
+++ b/core/tests/coretests/apks/install_verifier_good/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/keyset/res/values/strings.xml b/core/tests/coretests/apks/keyset/res/values/strings.xml
index ff99ffa..d811ec2 100644
--- a/core/tests/coretests/apks/keyset/res/values/strings.xml
+++ b/core/tests/coretests/apks/keyset/res/values/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
<string name="keyset_perm_desc">keyset_perm_description</string>
<string name="keyset_perm_label">keyset_perm_label</string>
</resources>
diff --git a/core/tests/coretests/apks/version/res/values/strings.xml b/core/tests/coretests/apks/version/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/version/res/values/strings.xml
+++ b/core/tests/coretests/apks/version/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/apks/version_nosys/res/values/strings.xml b/core/tests/coretests/apks/version_nosys/res/values/strings.xml
index 3b8b3b1..984152f 100644
--- a/core/tests/coretests/apks/version_nosys/res/values/strings.xml
+++ b/core/tests/coretests/apks/version_nosys/res/values/strings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Just need this dummy file to have something to build. -->
+<!-- Just need this placeholder file to have something to build. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="dummy">dummy</string>
+ <string name="placeholder">placeholder</string>
</resources>
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index af3660a..ae6e79a 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -20,7 +20,7 @@
public class VintfObjectTest extends TestCase {
/**
- * Sanity check for {@link VintfObject#report VintfObject.report()}.
+ * Quick check for {@link VintfObject#report VintfObject.report()}.
*/
public void testReport() {
String[] xmls = VintfObject.report();
diff --git a/data/keyboards/Vendor_2dc8_Product_6101.kl b/data/keyboards/Vendor_2dc8_Product_6101.kl
new file mode 100644
index 0000000..ec9f558
--- /dev/null
+++ b/data/keyboards/Vendor_2dc8_Product_6101.kl
@@ -0,0 +1,55 @@
+# 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.
+
+#
+# 8BitDo - SN30 Pro gamepad in Android (D-Input) mode
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Button labeled as "A" but should really produce keycode "B"
+key 304 BUTTON_B
+# Button labeled as "B" but should really produce keycode "A"
+key 305 BUTTON_A
+# Button labeled as "X" but should really produce keycode "Y"
+key 307 BUTTON_Y
+# Button labeled as "Y" but should really produce keycode "X"
+key 308 BUTTON_X
+
+key 310 BUTTON_L1
+key 312 BUTTON_L2
+key 311 BUTTON_R1
+key 313 BUTTON_R2
+
+# Button "Start" does not emit event when gamepad is in Android mode
+# Button "Home"
+key 306 BUTTON_MODE
+key 314 BUTTON_SELECT
+key 315 BUTTON_START
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# Dpad
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 1da4344..b3103fd5 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -23,6 +23,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -157,7 +158,7 @@
protected RenderNode mRootNode;
private boolean mOpaque = true;
private boolean mForceDark = false;
- private boolean mIsWideGamut = false;
+ private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
/**
* Creates a new instance of a HardwareRenderer. The HardwareRenderer will default
@@ -167,7 +168,7 @@
ProcessInitializer.sInstance.initDisplayInfo();
mRootNode = RenderNode.adopt(nCreateRootRenderNode());
mRootNode.setClipToBounds(false);
- mNativeProxy = nCreateProxy(!mOpaque, mIsWideGamut, mRootNode.mNativeRenderNode);
+ mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
if (mNativeProxy == 0) {
throw new OutOfMemoryError("Unable to create hardware renderer");
}
@@ -619,17 +620,17 @@
}
/**
- * Enable/disable wide gamut rendering on this renderer. Whether or not the actual rendering
- * will be wide gamut depends on the hardware support for such rendering.
+ * Sets the desired color mode on this renderer. Whether or not the actual rendering
+ * will use the requested colorMode depends on the hardware support for such rendering.
*
- * @param wideGamut true if this renderer should render in wide gamut, false if it should
- * render in sRGB
- * TODO: Figure out color...
+ * @param colorMode The @{@link ActivityInfo.ColorMode} to request
* @hide
*/
- public void setWideGamut(boolean wideGamut) {
- mIsWideGamut = wideGamut;
- nSetWideGamut(mNativeProxy, wideGamut);
+ public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
+ if (mColorMode != colorMode) {
+ mColorMode = colorMode;
+ nSetColorMode(mNativeProxy, colorMode);
+ }
}
/**
@@ -804,11 +805,6 @@
nSetPictureCaptureCallback(mNativeProxy, callback);
}
- /** @hide */
- public boolean isWideGamut() {
- return mIsWideGamut;
- }
-
/** called by native */
static void invokePictureCapturedCallback(long picturePtr, PictureCapturedCallback callback) {
Picture picture = new Picture(picturePtr);
@@ -1207,8 +1203,7 @@
private static native long nCreateRootRenderNode();
- private static native long nCreateProxy(boolean translucent, boolean isWideGamut,
- long rootRenderNode);
+ private static native long nCreateProxy(boolean translucent, long rootRenderNode);
private static native void nDeleteProxy(long nativeProxy);
@@ -1230,7 +1225,7 @@
private static native void nSetOpaque(long nativeProxy, boolean opaque);
- private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
+ private static native void nSetColorMode(long nativeProxy, int colorMode);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
index ddced59..ea79b73 100644
--- a/graphics/proto/Android.bp
+++ b/graphics/proto/Android.bp
@@ -1,10 +1,10 @@
java_library_static {
- name: "game-driver-protos",
+ name: "updatable-driver-protos",
host_supported: true,
proto: {
type: "lite",
},
- srcs: ["game_driver.proto"],
+ srcs: ["updatable_driver.proto"],
jarjar_rules: "jarjar-rules.txt",
- sdk_version: "28",
+ sdk_version: "30",
}
diff --git a/graphics/proto/game_driver.proto b/graphics/proto/updatable_driver.proto
similarity index 77%
rename from graphics/proto/game_driver.proto
rename to graphics/proto/updatable_driver.proto
index fd7ffcc..cbc9424 100644
--- a/graphics/proto/game_driver.proto
+++ b/graphics/proto/updatable_driver.proto
@@ -16,16 +16,16 @@
syntax = "proto2";
-package android.gamedriver;
+package android.updatabledriver;
-option java_package = "android.gamedriver";
-option java_outer_classname = "GameDriverProto";
+option java_package = "android.updatabledriver";
+option java_outer_classname = "UpdatableDriverProto";
-message Blacklist {
+message Denylist {
optional int64 version_code = 1;
repeated string package_names = 2;
}
-message Blacklists {
- repeated Blacklist blacklists = 1;
+message Denylists {
+ repeated Denylist denylists = 1;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
index 92e5758..ca3a511 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
@@ -192,7 +192,7 @@
Rect featureRect = new Rect(left, top, right, bottom);
rotateRectToDisplayRotation(featureRect, displayId);
transformToWindowSpaceRect(featureRect, windowToken);
- if (!featureRect.isEmpty()) {
+ if (isNotZero(featureRect)) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
feature.setRect(featureRect);
feature.setType(type);
@@ -207,6 +207,10 @@
return features;
}
+ private static boolean isNotZero(Rect rect) {
+ return rect.height() > 0 || rect.width() > 0;
+ }
+
@Override
protected void onListenersChanged() {
if (mSettingsObserver == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 338ece5..aeda2d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -68,12 +68,15 @@
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
- public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ protected DisplayImeController(IWindowManager wmService, DisplayController displayController,
Handler mainHandler, TransactionPool transactionPool) {
mHandler = mainHandler;
mWmService = wmService;
mTransactionPool = transactionPool;
mDisplayController = displayController;
+ }
+
+ protected void startMonitorDisplays() {
mDisplayController.addDisplayWindowListener(this);
}
@@ -490,4 +493,29 @@
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
+
+ /** Builds {@link DisplayImeController} instance. */
+ public static class Builder {
+ private IWindowManager mWmService;
+ private DisplayController mDisplayController;
+ private Handler mHandler;
+ private TransactionPool mTransactionPool;
+
+ public Builder(IWindowManager wmService, DisplayController displayController,
+ Handler handler, TransactionPool transactionPool) {
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mHandler = handler;
+ mTransactionPool = transactionPool;
+ }
+
+ /** Builds and initializes {@link DisplayImeController} instance. */
+ public DisplayImeController build() {
+ DisplayImeController displayImeController = new DisplayImeController(mWmService,
+ mDisplayController, mHandler, mTransactionPool);
+ // Separates startMonitorDisplays from constructor to prevent circular init issue.
+ displayImeController.startMonitorDisplays();
+ return displayImeController;
+ }
+ }
}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 3893041..8ab7da5 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -101,7 +101,7 @@
},
},
sanitize: {
- blacklist: "libandroidfw_blacklist.txt",
+ blocklist: "libandroidfw_blocklist.txt",
},
}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index e351a46..e10a7f3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1717,6 +1717,10 @@
// The overlay must be signed with the same signature as the actor declared for the target
// resource
ACTOR_SIGNATURE = 0x00000080,
+
+ // The overlay must be signed with the same signature as the reference package declared
+ // in the SystemConfig
+ CONFIG_SIGNATURE = 0x00000100,
};
using PolicyBitmask = uint32_t;
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blocklist.txt
similarity index 100%
rename from libs/androidfw/libandroidfw_blacklist.txt
rename to libs/androidfw/libandroidfw_blocklist.txt
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index 72747e8..33264d5 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -25,7 +25,8 @@
namespace android {
namespace uirenderer {
-AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) {
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
@@ -67,8 +68,9 @@
textureRelease->unref(false);
}
-void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace,
- GrContext* context) {
+void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -81,7 +83,7 @@
}
}
-void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
+void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
if (mBackendTexture.isValid()) {
mUpdateProc(mImageCtx, context);
}
diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h
index acdd63c..06f51fc 100644
--- a/libs/hwui/AutoBackendTextureRelease.h
+++ b/libs/hwui/AutoBackendTextureRelease.h
@@ -31,7 +31,8 @@
*/
class AutoBackendTextureRelease final {
public:
- AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer);
+ AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer);
const GrBackendTexture& getTexture() const { return mBackendTexture; }
@@ -42,9 +43,11 @@
inline sk_sp<SkImage> getImage() const { return mImage; }
- void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context);
+ void makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context);
- void newBufferContent(GrContext* context);
+ void newBufferContent(GrDirectContext* context);
private:
// The only way to invoke dtor is with unref, when mUsageCount is 0.
diff --git a/libs/hwui/ColorMode.h b/libs/hwui/ColorMode.h
new file mode 100644
index 0000000..6d387f9
--- /dev/null
+++ b/libs/hwui/ColorMode.h
@@ -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.
+ */
+
+#pragma once
+
+namespace android::uirenderer {
+
+// Must match the constants in ActivityInfo.java
+enum class ColorMode {
+ // SRGB means HWUI will produce buffer in SRGB color space.
+ Default = 0,
+ // WideColorGamut selects the most optimal colorspace & format for the device's display
+ // Most commonly DisplayP3 + RGBA_8888 currently.
+ WideColorGamut = 1,
+ // HDR Rec2020 + F16
+ Hdr = 2,
+ // HDR Rec2020 + 1010102
+ Hdr10 = 3,
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 67d8c07..6589dbd 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -189,7 +189,7 @@
sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer,
android_dataspace dataspace,
bool forceCreate,
- GrContext* context) {
+ GrDirectContext* context) {
if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace ||
forceCreate || mBuffer != buffer) {
if (buffer != mBuffer) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 05f3774..6731e9c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -106,7 +106,7 @@
~ImageSlot() { clear(); }
sk_sp<SkImage> createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace,
- bool forceCreate, GrContext* context);
+ bool forceCreate, GrDirectContext* context);
private:
void clear();
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index c2d2ff8..8724442 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -21,7 +21,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkCanvas.h>
#include <SkImage.h>
#include <utils/GLUtils.h>
@@ -285,7 +285,7 @@
return (image.get() != nullptr);
}
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
renderthread::VulkanManager mVulkanManager;
std::mutex mVkLock;
};
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 0dea354..b71bb07 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -118,7 +118,7 @@
}
int imgWidth = image->width();
int imgHeight = image->height();
- sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
+ sk_sp<GrDirectContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
if (bitmap->colorType() == kRGBA_F16_SkColorType &&
!grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 42743db..7d6875f 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -143,11 +143,10 @@
}
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
- jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
+ jboolean translucent, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
- proxy->setWideGamut(isWideGamut);
return (jlong) proxy;
}
@@ -218,10 +217,10 @@
proxy->setOpaque(opaque);
}
-static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jboolean wideGamut) {
+static void android_view_ThreadedRenderer_setColorMode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint colorMode) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setWideGamut(wideGamut);
+ proxy->setColorMode(static_cast<ColorMode>(colorMode));
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
@@ -659,7 +658,7 @@
(void*)android_view_ThreadedRenderer_setProcessStatsBuffer},
{"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid},
{"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode},
- {"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
+ {"nCreateProxy", "(ZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
{"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy},
{"nLoadSystemProperties", "(J)Z",
(void*)android_view_ThreadedRenderer_loadSystemProperties},
@@ -671,7 +670,7 @@
{"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
{"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry},
{"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque},
- {"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut},
+ {"nSetColorMode", "(JI)V", (void*)android_view_ThreadedRenderer_setColorMode},
{"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame},
{"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy},
{"nRegisterAnimatingRenderNode", "(JJ)V",
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 14a297f..dd0fc69 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,7 +15,7 @@
*/
#include "GLFunctorDrawable.h"
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <private/hwui/DrawGlInfo.h>
#include "FunctorDrawable.h"
#include "GrBackendSurface.h"
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f839213e..f95f347 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -29,7 +29,7 @@
void LayerDrawable::onDraw(SkCanvas* canvas) {
Layer* layer = mLayerUpdater->backingLayer();
if (layer) {
- DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true);
+ DrawLayer(canvas->recordingContext(), canvas, layer, nullptr, nullptr, true);
}
}
@@ -67,8 +67,12 @@
isIntegerAligned(dstDevRect.y()));
}
-bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* srcRect, const SkRect* dstRect,
+// TODO: Context arg probably doesn't belong here – do debug check at callsite instead.
+bool LayerDrawable::DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
bool useLayerTransform) {
if (context == nullptr) {
SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 7cd515a..ffbb480 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -32,8 +32,12 @@
public:
explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
- static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect,
- const SkRect* dstRect, bool useLayerTransform);
+ static bool DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
+ bool useLayerTransform);
protected:
virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 24a6228..389fe7e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -87,6 +87,8 @@
// Note: The default preference of pixel format is RGBA_8888, when other
// pixel format is available, we should branch out and do more check.
fboInfo.fFormat = GL_RGBA8;
+ } else if (colorType == kRGBA_1010102_SkColorType) {
+ fboInfo.fFormat = GL_RGB10_A2;
} else {
LOG_ALWAYS_FATAL("Unsupported color type.");
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 89a1c71..6dd3698 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -35,6 +35,7 @@
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
+#include "utils/Color.h"
#include "utils/String8.h"
#include "utils/TraceUtils.h"
@@ -587,14 +588,23 @@
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
mColorMode = colorMode;
- if (colorMode == ColorMode::SRGB) {
- mSurfaceColorType = SkColorType::kN32_SkColorType;
- mSurfaceColorSpace = SkColorSpace::MakeSRGB();
- } else if (colorMode == ColorMode::WideColorGamut) {
- mSurfaceColorType = DeviceInfo::get()->getWideColorType();
- mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ mSurfaceColorType = SkColorType::kN32_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeSRGB();
+ break;
+ case ColorMode::WideColorGamut:
+ mSurfaceColorType = DeviceInfo::get()->getWideColorType();
+ mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
+ break;
+ case ColorMode::Hdr:
+ mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
+ case ColorMode::Hdr10:
+ mSurfaceColorType = SkColorType::kRGBA_1010102_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 8341164..100bfb6 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -50,7 +50,7 @@
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
- void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
+ void setSurfaceColorProperties(ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -76,7 +76,7 @@
renderthread::RenderThread& mRenderThread;
- renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
+ ColorMode mColorMode = ColorMode::Default;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a362bd2..13d544c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -174,7 +174,10 @@
} else {
mNativeSurface = nullptr;
}
+ setupPipelineSurface();
+}
+void CanvasContext::setupPipelineSurface() {
bool hasSurface = mRenderPipeline->setSurface(
mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
@@ -184,7 +187,7 @@
mFrameNumber = -1;
- if (window != nullptr && hasSurface) {
+ if (mNativeSurface != nullptr && hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
// Enable frame stats after the surface has been bound to the appropriate graphics API.
@@ -239,9 +242,9 @@
mOpaque = opaque;
}
-void CanvasContext::setWideGamut(bool wideGamut) {
- ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- mRenderPipeline->setSurfaceColorProperties(colorMode);
+void CanvasContext::setColorMode(ColorMode mode) {
+ mRenderPipeline->setSurfaceColorProperties(mode);
+ setupPipelineSurface();
}
bool CanvasContext::makeCurrent() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0306eec..cba710f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -30,6 +30,7 @@
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
+#include "ColorMode.h"
#include <SkBitmap.h>
#include <SkRect.h>
@@ -119,7 +120,7 @@
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
- void setWideGamut(bool wideGamut);
+ void setColorMode(ColorMode mode);
bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
@@ -211,6 +212,7 @@
bool isSwapChainStuffed();
bool surfaceRequiresRedraw();
void setPresentTime();
+ void setupPipelineSurface();
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c701353..2a8aa8c 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -76,6 +76,7 @@
bool glColorSpace = false;
bool scRGB = false;
bool displayP3 = false;
+ bool hdr = false;
bool contextPriority = false;
bool surfacelessContext = false;
bool nativeFenceSync = false;
@@ -86,7 +87,8 @@
EglManager::EglManager()
: mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
- , mEglConfigWideGamut(nullptr)
+ , mEglConfigF16(nullptr)
+ , mEglConfig1010102(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE)
@@ -143,8 +145,7 @@
} else {
LOG_ALWAYS_FATAL("Unsupported wide color space.");
}
- mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension &&
- mEglConfigWideGamut != EGL_NO_CONFIG_KHR;
+ mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
@@ -177,6 +178,35 @@
return config;
}
+EGLConfig EglManager::load1010102Config(EGLDisplay display, SwapBehavior swapBehavior) {
+ EGLint eglSwapBehavior =
+ (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ // If we reached this point, we have a valid swap behavior
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 10,
+ EGL_GREEN_SIZE,
+ 10,
+ EGL_BLUE_SIZE,
+ 10,
+ EGL_ALPHA_SIZE,
+ 2,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ STENCIL_BUFFER_SIZE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | eglSwapBehavior,
+ EGL_NONE};
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ EGLint numConfigs = 1;
+ if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
+ return EGL_NO_CONFIG_KHR;
+ }
+ return config;
+}
+
EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
EGLint eglSwapBehavior =
(swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
@@ -230,6 +260,7 @@
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
+ EglExtensions.hdr = extensions.has("EGL_EXT_gl_colorspace_bt2020_pq");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync");
@@ -260,18 +291,20 @@
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
- SkColorType wideColorType = DeviceInfo::get()->getWideColorType();
// When we reach this point, we have a valid swap behavior
- if (wideColorType == SkColorType::kRGBA_F16_SkColorType && EglExtensions.pixelFormatFloat) {
- mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
- if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
+ if (EglExtensions.pixelFormatFloat) {
+ mEglConfigF16 = loadFP16Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
EglExtensions.pixelFormatFloat = false;
}
- } else if (wideColorType == SkColorType::kN32_SkColorType) {
- mEglConfigWideGamut = load8BitsConfig(mEglDisplay, mSwapBehavior);
+ }
+ mEglConfig1010102 = load1010102Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfig1010102 == EGL_NO_CONFIG_KHR) {
+ ALOGW("Failed to initialize 101010-2 format, error = %s",
+ eglErrorString());
}
}
@@ -311,8 +344,9 @@
sk_sp<SkColorSpace> colorSpace) {
LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
- bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
- EglExtensions.noConfigContext;
+ if (!mHasWideColorGamutSupport || !EglExtensions.noConfigContext) {
+ colorMode = ColorMode::Default;
+ }
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -338,26 +372,47 @@
// list is considered empty if the first entry is EGL_NONE
EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
+ EGLConfig config = mEglConfig;
+ if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) {
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
+ colorMode = ColorMode::Default;
+ } else {
+ config = mEglConfigF16;
+ }
+ }
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
- if (wideColorGamut) {
- skcms_Matrix3x3 colorGamut;
- LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
- } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ break;
+ case ColorMode::WideColorGamut: {
+ skcms_Matrix3x3 colorGamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
+ "Could not get gamut matrix from color space");
+ if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ break;
}
- } else {
- attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ case ColorMode::Hdr:
+ config = mEglConfigF16;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
+ case ColorMode::Hdr10:
+ config = mEglConfig1010102;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
}
}
- EGLSurface surface = eglCreateWindowSurface(
- mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, config, window, attribs);
if (surface == EGL_NO_SURFACE) {
return Error<EGLint>{eglGetError()};
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index f67fb31..69f3ed0 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -88,6 +88,7 @@
static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior);
static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior);
+ static EGLConfig load1010102Config(EGLDisplay display, SwapBehavior swapBehavior);
void initExtensions();
void createPBufferSurface();
@@ -97,7 +98,8 @@
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
- EGLConfig mEglConfigWideGamut;
+ EGLConfig mEglConfigF16;
+ EGLConfig mEglConfig1010102;
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index c3c2286..a04738d 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -22,6 +22,7 @@
#include "Lighting.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
+#include "ColorMode.h"
#include <SkRect.h>
#include <utils/RefBase.h>
@@ -42,16 +43,6 @@
enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
-enum class ColorMode {
- // SRGB means HWUI will produce buffer in SRGB color space.
- SRGB,
- // WideColorGamut means HWUI would support rendering scRGB non-linear into
- // a signed buffer with enough range to support the wide color gamut of the
- // display.
- WideColorGamut,
- // Hdr
-};
-
class Frame;
class IRenderPipeline {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index b764f74b..aad0cca 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -109,8 +109,8 @@
mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
-void RenderProxy::setWideGamut(bool wideGamut) {
- mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
+void RenderProxy::setColorMode(ColorMode mode) {
+ mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
}
int64_t* RenderProxy::frameInfo() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 16eabad..33dabc9 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -24,6 +24,7 @@
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
+#include "ColorMode.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
@@ -77,7 +78,7 @@
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
- void setWideGamut(bool wideGamut);
+ void setColorMode(ColorMode mode);
int64_t* frameInfo();
int syncAndDrawFrame();
void destroy();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 206b58f..565fb61 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -190,7 +190,7 @@
auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto size = glesVersion ? strlen(glesVersion) : -1;
cacheManager().configureContext(&options, glesVersion, size);
- sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
+ sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -204,7 +204,7 @@
initGrContextOptions(options);
auto vkDriverVersion = mVkManager->getDriverVersion();
cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion));
- sk_sp<GrContext> grContext = mVkManager->createContext(options);
+ sk_sp<GrDirectContext> grContext = mVkManager->createContext(options);
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -263,7 +263,7 @@
return *mReadback;
}
-void RenderThread::setGrContext(sk_sp<GrContext> context) {
+void RenderThread::setGrContext(sk_sp<GrDirectContext> context) {
mCacheManager->reset(context);
if (mGrContext) {
mRenderState->onContextDestroyed();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 2c295bc..b8ce556 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -17,7 +17,7 @@
#ifndef RENDERTHREAD_H_
#define RENDERTHREAD_H_
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkBitmap.h>
#include <apex/choreographer.h>
#include <cutils/compiler.h>
@@ -106,8 +106,8 @@
ProfileDataContainer& globalProfileData() { return mGlobalProfileData; }
Readback& readback();
- GrContext* getGrContext() const { return mGrContext.get(); }
- void setGrContext(sk_sp<GrContext> cxt);
+ GrDirectContext* getGrContext() const { return mGrContext.get(); }
+ void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
VulkanManager& vulkanManager() { return *mVkManager; }
@@ -186,7 +186,7 @@
ProfileDataContainer mGlobalProfileData;
Readback* mReadback = nullptr;
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
VulkanManager* mVkManager;
};
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3cb1607..249936e 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -20,7 +20,7 @@
#include <EGL/eglext.h>
#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <GrTypes.h>
#include <android/sync.h>
#include <ui/FatVector.h>
@@ -369,7 +369,7 @@
}
}
-sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -388,7 +388,7 @@
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = std::move(getProc);
- return GrContext::MakeVulkan(backendContext, options);
+ return GrDirectContext::MakeVulkan(backendContext, options);
}
VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
@@ -562,9 +562,11 @@
delete surface;
}
-VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers) {
LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized");
if (!window) {
@@ -575,7 +577,7 @@
*this, extraBuffers);
}
-status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
+status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
if (!hasVkContext()) {
ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
return INVALID_OPERATION;
@@ -623,7 +625,7 @@
return OK;
}
-status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) {
+status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* grContext) {
*nativeFence = -1;
if (!hasVkContext()) {
ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 8b19f13..3f2df8d 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -57,9 +57,11 @@
bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
// Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
- VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
+ VulkanSurface* createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers);
void destroySurface(VulkanSurface* surface);
@@ -70,18 +72,18 @@
void destroy();
// Inserts a wait on fence command into the Vulkan command buffer.
- status_t fenceWait(int fence, GrContext* grContext);
+ status_t fenceWait(int fence, GrDirectContext* grContext);
// Creates a fence that is signaled when all the pending Vulkan commands are finished on the
// GPU.
- status_t createReleaseFence(int* nativeFence, GrContext* grContext);
+ status_t createReleaseFence(int* nativeFence, GrDirectContext* grContext);
// Returned pointers are owned by VulkanManager.
// An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrContext> createContext(const GrContextOptions& options);
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index a4d7b82..edd3e4e 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -26,7 +26,7 @@
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
-static size_t getCacheUsage(GrContext* grContext) {
+static size_t getCacheUsage(GrDirectContext* grContext) {
size_t cacheUsage;
grContext->getResourceCacheUsage(nullptr, &cacheUsage);
return cacheUsage;
@@ -35,7 +35,7 @@
RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
int32_t width = DeviceInfo::get()->getWidth();
int32_t height = DeviceInfo::get()->getHeight();
- GrContext* grContext = renderThread.getGrContext();
+ GrDirectContext* grContext = renderThread.getGrContext();
ASSERT_TRUE(grContext != nullptr);
// create pairs of offscreen render targets and images until we exceed the
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index ca1bf69..eff34a8 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -344,5 +344,27 @@
static_cast<uint8_t>(rgb.b * 255));
}
+// Note that SkColorSpace doesn't have the notion of an unspecified SDR white
+// level.
+static constexpr float kDefaultSDRWhiteLevel = 150.f;
+
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level) {
+ if (sdr_white_level <= 0.f) {
+ sdr_white_level = kDefaultSDRWhiteLevel;
+ }
+ // The generic PQ transfer function produces normalized luminance values i.e.
+ // the range 0-1 represents 0-10000 nits for the reference display, but we
+ // want to map 1.0 to |sdr_white_level| nits so we need to scale accordingly.
+ const double w = 10000. / sdr_white_level;
+ // Distribute scaling factor W by scaling A and B with X ^ (1/F):
+ // ((A + Bx^C) / (D + Ex^C))^F * W = ((A + Bx^C) / (D + Ex^C) * W^(1/F))^F
+ // See https://crbug.com/1058580#c32 for discussion.
+ skcms_TransferFunction fn = SkNamedTransferFn::kPQ;
+ const double ws = pow(w, 1. / fn.f);
+ fn.a = ws * fn.a;
+ fn.b = ws * fn.b;
+ return fn;
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 71ed683..1654072 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -126,6 +126,7 @@
Lab sRGBToLab(SkColor color);
SkColor LabToSRGB(const Lab& lab, SkAlpha alpha);
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level = 0.f);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3ac71b2..4c03fd1 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -564,6 +564,7 @@
* request is from a hardware key press. (e.g. {@link MediaController}).
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int FLAG_FROM_KEY = 1 << 12;
// The iterator of TreeMap#entrySet() returns the entries in ascending key order.
@@ -3801,7 +3802,7 @@
final IAudioService service = getService();
try {
service.unregisterAudioPolicyAsync(policy.cb());
- policy.setRegistration(null);
+ policy.reset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3823,7 +3824,7 @@
try {
policy.invalidateCaptorsAndInjectors();
service.unregisterAudioPolicy(policy.cb());
- policy.setRegistration(null);
+ policy.reset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4d26b8d..c9cdbb0 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -487,6 +487,11 @@
}
}
+ /** @hide */
+ public AudioAttributes getAudioAttributes() {
+ return mAudioAttributes;
+ }
+
/**
* Builder class for {@link AudioRecord} objects.
* Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4a6724a..57e8e43 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -70,16 +70,17 @@
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
/**
- * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
+ * This is a class for reading and writing Exif tags in various image file formats.
* <p>
- * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF and HEIF.
+ * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
* <p>
- * Attribute mutation is supported for JPEG image files.
+ * Supported for writing: JPEG, PNG, WebP.
* <p>
* Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
@@ -585,6 +586,15 @@
private static final int WEBP_FILE_SIZE_BYTE_LENGTH = 4;
private static final byte[] WEBP_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x45, (byte) 0x58,
(byte) 0x49, (byte) 0x46};
+ private static final byte[] WEBP_VP8_SIGNATURE = new byte[]{(byte) 0x9d, (byte) 0x01,
+ (byte) 0x2a};
+ private static final byte WEBP_VP8L_SIGNATURE = (byte) 0x2f;
+ private static final byte[] WEBP_CHUNK_TYPE_VP8X = "VP8X".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8L = "VP8L".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8 = "VP8 ".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANIM = "ANIM".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANMF = "ANMF".getBytes(Charset.defaultCharset());
+ private static final int WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH = 10;
private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
@@ -1609,7 +1619,7 @@
}
/**
- * Returns whether ExifInterface currently supports parsing data from the specified mime type
+ * Returns whether ExifInterface currently supports reading data from the specified mime type
* or not.
*
* @param mimeType the string value of mime type
@@ -1633,6 +1643,8 @@
case "image/x-fuji-raf":
case "image/heic":
case "image/heif":
+ case "image/png":
+ case "image/webp":
return true;
default:
return false;
@@ -2046,18 +2058,21 @@
* {@link #setAttribute(String,String)} to set all attributes to write and
* make a single call rather than multiple calls for each attribute.
* <p>
- * This method is only supported for JPEG and PNG files.
+ * This method is supported for JPEG, PNG and WebP files.
* <p class="note">
* Note: after calling this method, any attempts to obtain range information
* from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
* will throw {@link IllegalStateException}, since the offsets may have
* changed in the newly written file.
+ * <p>
+ * For WebP format, the Exif data will be stored as an Extended File Format, and it may not be
+ * supported for older readers.
* </p>
*/
public void saveAttributes() throws IOException {
- if (!mIsSupportedFile || (mMimeType != IMAGE_TYPE_JPEG && mMimeType != IMAGE_TYPE_PNG)) {
- throw new IOException("ExifInterface only supports saving attributes on JPEG or PNG "
- + "formats.");
+ if (!isSupportedFormatForSavingAttributes()) {
+ throw new IOException("ExifInterface only supports saving attributes on JPEG, PNG, "
+ + "or WebP formats.");
}
if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
throw new IOException(
@@ -2081,16 +2096,15 @@
try {
// Move the original file to temporary file.
if (mFilename != null) {
- tempFile = new File(mFilename + ".tmp");
+ String parent = originalFile.getParent();
+ String name = originalFile.getName();
+ String tempPrefix = UUID.randomUUID().toString() + "_";
+ tempFile = new File(parent, tempPrefix + name);
if (!originalFile.renameTo(tempFile)) {
throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
}
} else if (mSeekableFileDescriptor != null) {
- if (mMimeType == IMAGE_TYPE_JPEG) {
- tempFile = File.createTempFile("temp", "jpg");
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- tempFile = File.createTempFile("temp", "png");
- }
+ tempFile = File.createTempFile("temp", "tmp");
Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
in = new FileInputStream(mSeekableFileDescriptor);
out = new FileOutputStream(tempFile);
@@ -2120,6 +2134,8 @@
saveJpegAttributes(bufferedIn, bufferedOut);
} else if (mMimeType == IMAGE_TYPE_PNG) {
savePngAttributes(bufferedIn, bufferedOut);
+ } else if (mMimeType == IMAGE_TYPE_WEBP) {
+ saveWebpAttributes(bufferedIn, bufferedOut);
}
}
} catch (Exception e) {
@@ -2601,7 +2617,6 @@
ByteOrderedDataInputStream signatureInputStream = null;
try {
signatureInputStream = new ByteOrderedDataInputStream(signatureCheckBytes);
- signatureInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
long chunkSize = signatureInputStream.readInt();
byte[] chunkType = new byte[4];
@@ -3392,6 +3407,9 @@
bytesRead += in.skipBytes(WEBP_SIGNATURE_2.length);
try {
while (true) {
+ // TODO: Check the first Chunk Type, and if it is VP8X, check if the chunks are
+ // ordered properly.
+
// Each chunk is made up of three parts:
// 1) Chunk FourCC: 4-byte concatenating four ASCII characters.
// 2) Chunk Size: 4-byte unsigned integer indicating the size of the chunk.
@@ -3417,6 +3435,9 @@
// Save offset values for handling thumbnail and attribute offsets.
mExifOffset = bytesRead;
readExifSegment(payload, IFD_TYPE_PRIMARY);
+
+ // Save offset values for handleThumbnailFromJfif() function
+ mExifOffset = bytesRead;
break;
} else {
// Add a single padding byte at end if chunk size is odd
@@ -3610,6 +3631,263 @@
copy(dataInputStream, dataOutputStream);
}
+ // A WebP file has a header and a series of chunks.
+ // The header is composed of:
+ // "RIFF" + File Size + "WEBP"
+ //
+ // The structure of the chunks can be divided largely into two categories:
+ // 1) Contains only image data,
+ // 2) Contains image data and extra data.
+ // In the first category, there is only one chunk: type "VP8" (compression with loss) or "VP8L"
+ // (lossless compression).
+ // In the second category, the first chunk will be of type "VP8X", which contains flags
+ // indicating which extra data exist in later chunks. The proceeding chunks must conform to
+ // the following order based on type (if they exist):
+ // Color Profile ("ICCP") + Animation Control Data ("ANIM") + Image Data ("VP8"/"VP8L")
+ // + Exif metadata ("EXIF") + XMP metadata ("XMP")
+ //
+ // And in order to have EXIF data, a WebP file must be of the second structure and thus follow
+ // the following rules:
+ // 1) "VP8X" chunk as the first chunk,
+ // 2) flag for EXIF inside "VP8X" chunk set to 1, and
+ // 3) contain the "EXIF" chunk in the correct order amongst other chunks.
+ //
+ // Based on these rules, this API will support three different cases depending on the contents
+ // of the original file:
+ // 1) "EXIF" chunk already exists
+ // -> replace it with the new "EXIF" chunk
+ // 2) "EXIF" chunk does not exist and the first chunk is "VP8" or "VP8L"
+ // -> add "VP8X" before the "VP8"/"VP8L" chunk (with EXIF flag set to 1), and add new
+ // "EXIF" chunk after the "VP8"/"VP8L" chunk.
+ // 3) "EXIF" chunk does not exist and the first chunk is "VP8X"
+ // -> set EXIF flag in "VP8X" chunk to 1, and add new "EXIF" chunk at the proper location.
+ //
+ // See https://developers.google.com/speed/webp/docs/riff_container for more details.
+ private void saveWebpAttributes(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ if (DEBUG) {
+ Log.d(TAG, "saveWebpAttributes starting with (inputStream: " + inputStream
+ + ", outputStream: " + outputStream + ")");
+ }
+ ByteOrderedDataInputStream totalInputStream =
+ new ByteOrderedDataInputStream(inputStream, ByteOrder.LITTLE_ENDIAN);
+ ByteOrderedDataOutputStream totalOutputStream =
+ new ByteOrderedDataOutputStream(outputStream, ByteOrder.LITTLE_ENDIAN);
+
+ // WebP signature
+ copy(totalInputStream, totalOutputStream, WEBP_SIGNATURE_1.length);
+ // File length will be written after all the chunks have been written
+ totalInputStream.skipBytes(WEBP_FILE_SIZE_BYTE_LENGTH + WEBP_SIGNATURE_2.length);
+
+ // Create a separate byte array to calculate file length
+ ByteArrayOutputStream nonHeaderByteArrayOutputStream = null;
+ try {
+ nonHeaderByteArrayOutputStream = new ByteArrayOutputStream();
+ ByteOrderedDataOutputStream nonHeaderOutputStream =
+ new ByteOrderedDataOutputStream(nonHeaderByteArrayOutputStream,
+ ByteOrder.LITTLE_ENDIAN);
+
+ if (mExifOffset != 0) {
+ // EXIF chunk exists in the original file
+ // Tested by webp_with_exif.webp
+ int bytesRead = WEBP_SIGNATURE_1.length + WEBP_FILE_SIZE_BYTE_LENGTH
+ + WEBP_SIGNATURE_2.length;
+ copy(totalInputStream, nonHeaderOutputStream,
+ mExifOffset - bytesRead - WEBP_CHUNK_TYPE_BYTE_LENGTH
+ - WEBP_CHUNK_SIZE_BYTE_LENGTH);
+
+ // Skip input stream to the end of the EXIF chunk
+ totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
+ int exifChunkLength = totalInputStream.readInt();
+ totalInputStream.skipBytes(exifChunkLength);
+
+ // Write new EXIF chunk to output stream
+ int exifSize = writeExifSegment(nonHeaderOutputStream);
+ } else {
+ // EXIF chunk does not exist in the original file
+ byte[] firstChunkType = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (totalInputStream.read(firstChunkType) != firstChunkType.length) {
+ throw new IOException("Encountered invalid length while parsing WebP chunk "
+ + "type");
+ }
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8X)) {
+ // Original file already includes other extra data
+ int size = totalInputStream.readInt();
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ byte[] data = new byte[(size % 2) == 1 ? size + 1 : size];
+ totalInputStream.read(data);
+
+ // Set the EXIF flag to 1
+ data[0] = (byte) (data[0] | (1 << 3));
+
+ // Retrieve Animation flag--in order to check where EXIF data should start
+ boolean containsAnimation = ((data[0] >> 1) & 1) == 1;
+
+ // Write the original VP8X chunk
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(size);
+ nonHeaderOutputStream.write(data);
+
+ // Animation control data is composed of 1 ANIM chunk and multiple ANMF
+ // chunks and since the image data (VP8/VP8L) chunks are included in the ANMF
+ // chunks, EXIF data should come after the last ANMF chunk.
+ // Also, because there is no value indicating the amount of ANMF chunks, we need
+ // to keep iterating through chunks until we either reach the end of the file or
+ // the XMP chunk (if it exists).
+ // Tested by webp_with_anim_without_exif.webp
+ if (containsAnimation) {
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_ANIM, null);
+
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ int read = inputStream.read(type);
+ if (!Arrays.equals(type, WEBP_CHUNK_TYPE_ANMF)) {
+ // Either we have reached EOF or the start of a non-ANMF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ break;
+ }
+ copyWebPChunk(totalInputStream, nonHeaderOutputStream, type);
+ }
+ } else {
+ // Skip until we find the VP8 or VP8L chunk
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_VP8, WEBP_CHUNK_TYPE_VP8L);
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)
+ || Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ int size = totalInputStream.readInt();
+ int bytesToRead = size;
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ if (size % 2 == 1) {
+ bytesToRead += 1;
+ }
+
+ // Retrieve image width/height
+ int widthAndHeight = 0;
+ int width = 0;
+ int height = 0;
+ int alpha = 0;
+ // Save VP8 frame data for later
+ byte[] vp8Frame = new byte[3];
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ totalInputStream.read(vp8Frame);
+
+ // Check signature
+ byte[] vp8Signature = new byte[3];
+ if (totalInputStream.read(vp8Signature) != vp8Signature.length
+ || !Arrays.equals(WEBP_VP8_SIGNATURE, vp8Signature)) {
+ throw new IOException("Encountered error while checking VP8 "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ width = (widthAndHeight << 18) >> 18;
+ height = (widthAndHeight << 2) >> 18;
+ bytesToRead -= (vp8Frame.length + vp8Signature.length + 4);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ // Check signature
+ byte vp8lSignature = totalInputStream.readByte();
+ if (vp8lSignature != WEBP_VP8L_SIGNATURE) {
+ throw new IOException("Encountered error while checking VP8L "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ // VP8L stores width - 1 and height - 1 values. See "2 RIFF Header" of
+ // "WebP Lossless Bitstream Specification"
+ width = ((widthAndHeight << 18) >> 18) + 1;
+ height = ((widthAndHeight << 4) >> 18) + 1;
+ // Retrieve alpha bit
+ alpha = widthAndHeight & (1 << 3);
+ bytesToRead -= (1 /* VP8L signature */ + 4);
+ }
+
+ // Create VP8X with Exif flag set to 1
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH);
+ byte[] data = new byte[WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH];
+ // EXIF flag
+ data[0] = (byte) (data[0] | (1 << 3));
+ // ALPHA flag
+ data[0] = (byte) (data[0] | (alpha << 4));
+ // VP8X stores Width - 1 and Height - 1 values
+ width -= 1;
+ height -= 1;
+ data[4] = (byte) width;
+ data[5] = (byte) (width >> 8);
+ data[6] = (byte) (width >> 16);
+ data[7] = (byte) height;
+ data[8] = (byte) (height >> 8);
+ data[9] = (byte) (height >> 16);
+ nonHeaderOutputStream.write(data);
+
+ // Write VP8 or VP8L data
+ nonHeaderOutputStream.write(firstChunkType);
+ nonHeaderOutputStream.writeInt(size);
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ nonHeaderOutputStream.write(vp8Frame);
+ nonHeaderOutputStream.write(WEBP_VP8_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ nonHeaderOutputStream.write(WEBP_VP8L_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ }
+ copy(totalInputStream, nonHeaderOutputStream, bytesToRead);
+
+ // Write EXIF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ }
+
+ // Copy the rest of the file
+ copy(totalInputStream, nonHeaderOutputStream);
+
+ // Write file length + second signature
+ totalOutputStream.writeInt(nonHeaderByteArrayOutputStream.size()
+ + WEBP_SIGNATURE_2.length);
+ totalOutputStream.write(WEBP_SIGNATURE_2);
+ nonHeaderByteArrayOutputStream.writeTo(totalOutputStream);
+ } catch (Exception e) {
+ throw new IOException("Failed to save WebP file", e);
+ } finally {
+ closeQuietly(nonHeaderByteArrayOutputStream);
+ }
+ }
+
+ private void copyChunksUpToGivenChunkType(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] firstGivenType,
+ byte[] secondGivenType) throws IOException {
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (inputStream.read(type) != type.length) {
+ throw new IOException("Encountered invalid length while copying WebP chunks up to"
+ + "chunk type " + new String(firstGivenType, ASCII)
+ + ((secondGivenType == null) ? "" : " or " + new String(secondGivenType,
+ ASCII)));
+ }
+ copyWebPChunk(inputStream, outputStream, type);
+ if (Arrays.equals(type, firstGivenType)
+ || (secondGivenType != null && Arrays.equals(type, secondGivenType))) {
+ break;
+ }
+ }
+ }
+
+ private void copyWebPChunk(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] type) throws IOException {
+ int size = inputStream.readInt();
+ outputStream.write(type);
+ outputStream.writeInt(size);
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ copy(inputStream, outputStream, (size % 2) == 1 ? size + 1 : size);
+ }
+
// Reads the given EXIF byte area and save its tag data into attributes.
private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
ByteOrderedDataInputStream dataInputStream =
@@ -4360,14 +4638,22 @@
ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder));
}
- if (mMimeType == IMAGE_TYPE_JPEG) {
- // Write JPEG specific data (APP1 size, APP1 identifier)
- dataOutputStream.writeUnsignedShort(totalSize);
- dataOutputStream.write(IDENTIFIER_EXIF_APP1);
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- // Write PNG specific data (chunk size, chunk type)
- dataOutputStream.writeInt(totalSize);
- dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ switch (mMimeType) {
+ case IMAGE_TYPE_JPEG:
+ // Write JPEG specific data (APP1 size, APP1 identifier)
+ dataOutputStream.writeUnsignedShort(totalSize);
+ dataOutputStream.write(IDENTIFIER_EXIF_APP1);
+ break;
+ case IMAGE_TYPE_PNG:
+ // Write PNG specific data (chunk size, chunk type)
+ dataOutputStream.writeInt(totalSize);
+ dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ break;
+ case IMAGE_TYPE_WEBP:
+ // Write WebP specific data (chunk type, chunk size)
+ dataOutputStream.write(WEBP_CHUNK_TYPE_EXIF);
+ dataOutputStream.writeInt(totalSize);
+ break;
}
// Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
@@ -4436,6 +4722,11 @@
dataOutputStream.write(getThumbnailBytes());
}
+ // For WebP files, add a single padding byte at end if chunk size is odd
+ if (mMimeType == IMAGE_TYPE_WEBP && totalSize % 2 == 1) {
+ dataOutputStream.writeByte(0);
+ }
+
// Reset the byte order to big endian in order to write remaining parts of the JPEG file.
dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
@@ -4537,12 +4828,17 @@
private int mPosition;
public ByteOrderedDataInputStream(InputStream in) throws IOException {
+ this(in, ByteOrder.BIG_ENDIAN);
+ }
+
+ ByteOrderedDataInputStream(InputStream in, ByteOrder byteOrder) throws IOException {
mInputStream = in;
mDataInputStream = new DataInputStream(in);
mLength = mDataInputStream.available();
mPosition = 0;
// TODO (b/142218289): Need to handle case where input stream does not support mark
mDataInputStream.mark(mLength);
+ mByteOrder = byteOrder;
}
public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
@@ -4867,4 +5163,12 @@
}
}
}
+
+ private boolean isSupportedFormatForSavingAttributes() {
+ if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
+ || mMimeType == IMAGE_TYPE_WEBP)) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 87c3bb9..5dc6f75 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -198,7 +198,10 @@
* {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
* </tr>
* </table>
- * Using other combinations may result in {@link IllegalArgumentException}.
+ * Using other combinations may result in {@link IllegalArgumentException}. Additionally,
+ * specifying {@link HardwareBuffer#USAGE_CPU_WRITE_RARELY} or
+ * {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} and writing to the ImageReader's buffers
+ * might break assumptions made by some producers, and should be used with caution.
* </p>
* <p>
* If the {@link ImageReader} is used as an output target for a {@link
@@ -255,6 +258,7 @@
mWidth = width;
mHeight = height;
mFormat = format;
+ mUsage = usage;
mMaxImages = maxImages;
if (width < 1 || height < 1) {
@@ -768,6 +772,7 @@
private final int mWidth;
private final int mHeight;
private final int mFormat;
+ private final long mUsage;
private final int mMaxImages;
private final int mNumPlanes;
private final Surface mSurface;
@@ -909,7 +914,8 @@
throwISEIfImageIsInvalid();
if (mPlanes == null) {
- mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
+ mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat,
+ ImageReader.this.mUsage);
}
// Shallow copy is fine.
return mPlanes.clone();
@@ -1038,7 +1044,7 @@
private AtomicBoolean mIsDetached = new AtomicBoolean(false);
private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
- int readerFormat);
+ int readerFormat, long readerUsage);
private synchronized native int nativeGetWidth();
private synchronized native int nativeGetHeight();
private synchronized native int nativeGetFormat(int readerFormat);
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index d3e9c7e..8a17465 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -553,6 +553,12 @@
}
}
+ /** @hide */
+ public void reset() {
+ setRegistration(null);
+ mConfig.reset();
+ }
+
public void setRegistration(String regId) {
synchronized (mLock) {
mRegistrationId = regId;
@@ -566,6 +572,11 @@
sendMsg(MSG_POLICY_STATUS_CHANGE);
}
+ /**@hide*/
+ public String getRegistration() {
+ return mRegistrationId;
+ }
+
private boolean policyReadyToUse() {
synchronized (mLock) {
if (mStatus != POLICY_STATUS_REGISTERED) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 91b9bb3..561a884 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -162,7 +162,7 @@
public String toLogFriendlyString () {
String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
- textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n";
+ textDump += mMixes.size() + " AudioMix, reg:" + mRegistrationId + "\n";
for(AudioMix mix : mMixes) {
// write mix route flags
textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n";
@@ -220,6 +220,10 @@
return textDump;
}
+ protected void reset() {
+ mMixCounter = 0;
+ }
+
protected void setRegistration(String regId) {
final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
final boolean newRegNull = (regId == null) || regId.isEmpty();
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0a02156..bd2a0eaa7 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -675,7 +675,8 @@
return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
}
-static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
+static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image,
+ uint64_t ndkReaderUsage) {
ALOGV("%s", __FUNCTION__);
BufferItem* buffer = Image_getBufferItem(env, thiz);
if (buffer == NULL) {
@@ -684,8 +685,16 @@
return;
}
- status_t res = lockImageFromBuffer(buffer,
- GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
+ uint32_t lockUsage;
+ if ((ndkReaderUsage & (AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY
+ | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN)) != 0) {
+ lockUsage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ } else {
+ lockUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+ }
+
+ status_t res = lockImageFromBuffer(buffer, lockUsage, buffer->mFence->dup(), image);
+
if (res != OK) {
jniThrowExceptionFmt(env, "java/lang/RuntimeException",
"lock buffer failed for format 0x%x",
@@ -721,7 +730,7 @@
}
static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
- int numPlanes, int readerFormat)
+ int numPlanes, int readerFormat, uint64_t ndkReaderUsage)
{
ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
int rowStride = 0;
@@ -754,7 +763,7 @@
}
LockedImage lockedImg = LockedImage();
- Image_getLockedImage(env, thiz, &lockedImg);
+ Image_getLockedImage(env, thiz, &lockedImg, ndkReaderUsage);
if (env->ExceptionCheck()) {
return NULL;
}
@@ -839,7 +848,7 @@
};
static const JNINativeMethod gImageMethods[] = {
- {"nativeCreatePlanes", "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+ {"nativeCreatePlanes", "(IIJ)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
(void*)Image_createSurfacePlanes },
{"nativeGetWidth", "()I", (void*)Image_getWidth },
{"nativeGetHeight", "()I", (void*)Image_getHeight },
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 033a32f..55aac09 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -590,7 +590,7 @@
ALOGV("getSyncSettings: %d %d %f %f",
scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
- // sanity check params
+ // check params
if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
|| scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
|| scp.sync.mTolerance < 0.f
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
index f752008..d1ce30a 100644
--- a/media/jni/android_media_MediaSync.cpp
+++ b/media/jni/android_media_MediaSync.cpp
@@ -451,7 +451,7 @@
ALOGV("getSyncParams: %d %d %f %f",
scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
- // sanity check params
+ // check params
if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
|| scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
|| scs.sync.mTolerance < 0.f
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java b/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
index ce81a18..ab9ae8a 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterFunction.java
@@ -43,7 +43,7 @@
public Frame execute(KeyValueMap inputMap) {
int filterOutCount = mFilter.getNumberOfOutputs();
- // Sanity checks
+ // Validation checks
if (filterOutCount > 1) {
throw new RuntimeException("Calling execute on filter " + mFilter + " with multiple "
+ "outputs! Use executeMulti() instead!");
diff --git a/media/mca/filterfw/jni/jni_native_program.cpp b/media/mca/filterfw/jni/jni_native_program.cpp
index 1424607..cd4f718 100644
--- a/media/mca/filterfw/jni/jni_native_program.cpp
+++ b/media/mca/filterfw/jni/jni_native_program.cpp
@@ -134,7 +134,7 @@
jobject output) {
NativeProgram* program = ConvertFromJava<NativeProgram>(env, thiz);
- // Sanity checks
+ // Validation checks
if (!program || !inputs) {
return JNI_FALSE;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 0ae640d..e74bda8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -16,16 +16,6 @@
package com.android.mediaframeworktest.helpers;
-import com.android.ex.camera2.blocking.BlockingCameraManager;
-import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
-import com.android.ex.camera2.blocking.BlockingSessionCallback;
-import com.android.ex.camera2.blocking.BlockingStateCallback;
-import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
-
-import junit.framework.Assert;
-
-import org.mockito.Mockito;
-
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
@@ -64,6 +54,16 @@
import androidx.test.InstrumentationRegistry;
+import com.android.ex.camera2.blocking.BlockingCameraManager;
+import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
+import com.android.ex.camera2.blocking.BlockingSessionCallback;
+import com.android.ex.camera2.blocking.BlockingStateCallback;
+import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
+
+import junit.framework.Assert;
+
+import org.mockito.Mockito;
+
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
@@ -77,8 +77,8 @@
import java.util.Date;
import java.util.HashMap;
import java.util.List;
-import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@@ -225,7 +225,7 @@
}
/**
- * Dummy listener that release the image immediately once it is available.
+ * Mock listener that release the image immediately once it is available.
*
* <p>
* It can be used for the case where we don't care the image data at all.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
index 96b0424..a77b289 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/Preconditions.java
@@ -22,7 +22,7 @@
/**
* Helper set of methods to perform precondition checks before starting method execution.
*
- * <p>Typically used to sanity check arguments or the current object state.</p>
+ * <p>Typically used to check arguments or the current object state.</p>
*/
/**
* (non-Javadoc)
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
index b3f443b..9a64b58 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
@@ -16,7 +16,7 @@
package com.android.mediaframeworktest.helpers;
-import junit.framework.Assert;
+import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
import android.graphics.ImageFormat;
import android.graphics.Rect;
@@ -31,6 +31,8 @@
import android.util.Rational;
import android.util.Size;
+import junit.framework.Assert;
+
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,8 +42,6 @@
import java.util.List;
import java.util.Set;
-import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf;
-
/**
* Helpers to get common static info out of the camera.
*
@@ -435,7 +435,7 @@
}
/**
- * Get max AE regions and do sanity check.
+ * Get max AE regions and do validation check.
*
* @return AE max regions supported by the camera device
*/
@@ -448,7 +448,7 @@
}
/**
- * Get max AWB regions and do sanity check.
+ * Get max AWB regions and do validation check.
*
* @return AWB max regions supported by the camera device
*/
@@ -461,7 +461,7 @@
}
/**
- * Get max AF regions and do sanity check.
+ * Get max AF regions and do validation check.
*
* @return AF max regions supported by the camera device
*/
@@ -545,7 +545,7 @@
}
/**
- * Get available thumbnail sizes and do the sanity check.
+ * Get available thumbnail sizes and do the validation check.
*
* @return The array of available thumbnail sizes
*/
@@ -573,7 +573,7 @@
}
/**
- * Get available focal lengths and do the sanity check.
+ * Get available focal lengths and do the validation check.
*
* @return The array of available focal lengths
*/
@@ -594,7 +594,7 @@
}
/**
- * Get available apertures and do the sanity check.
+ * Get available apertures and do the validation check.
*
* @return The non-null array of available apertures
*/
@@ -909,7 +909,7 @@
}
/**
- * Get hyperfocalDistance and do the sanity check.
+ * Get hyperfocalDistance and do the validation check.
* <p>
* Note that, this tag is optional, will return -1 if this tag is not
* available.
@@ -1068,7 +1068,7 @@
}
/**
- * get android.control.availableModes and do the sanity check.
+ * get android.control.availableModes and do the validation check.
*
* @return available control modes.
*/
@@ -1124,7 +1124,7 @@
}
/**
- * Get aeAvailableModes and do the sanity check.
+ * Get aeAvailableModes and do the validation check.
*
* <p>Depending on the check level this class has, for WAR or COLLECT levels,
* If the aeMode list is invalid, return an empty mode array. The the caller doesn't
@@ -1196,7 +1196,7 @@
}
/**
- * Get available AWB modes and do the sanity check.
+ * Get available AWB modes and do the validation check.
*
* @return array that contains available AWB modes, empty array if awbAvailableModes is
* unavailable.
@@ -1222,7 +1222,7 @@
}
/**
- * Get available AF modes and do the sanity check.
+ * Get available AF modes and do the validation check.
*
* @return array that contains available AF modes, empty array if afAvailableModes is
* unavailable.
@@ -1580,7 +1580,7 @@
}
/**
- * Get value of key android.control.aeCompensationStep and do the sanity check.
+ * Get value of key android.control.aeCompensationStep and do the validation check.
*
* @return default value if the value is null.
*/
@@ -1605,7 +1605,7 @@
}
/**
- * Get value of key android.control.aeCompensationRange and do the sanity check.
+ * Get value of key android.control.aeCompensationRange and do the validation check.
*
* @return default value if the value is null or malformed.
*/
@@ -1635,7 +1635,7 @@
}
/**
- * Get availableVideoStabilizationModes and do the sanity check.
+ * Get availableVideoStabilizationModes and do the validation check.
*
* @return available video stabilization modes, empty array if it is unavailable.
*/
@@ -1666,7 +1666,7 @@
}
/**
- * Get availableOpticalStabilization and do the sanity check.
+ * Get availableOpticalStabilization and do the validation check.
*
* @return available optical stabilization modes, empty array if it is unavailable.
*/
@@ -1780,7 +1780,7 @@
}
/**
- * Get max pipeline depth and do the sanity check.
+ * Get max pipeline depth and do the validation check.
*
* @return max pipeline depth, default value if it is not available.
*/
@@ -1846,7 +1846,7 @@
/**
- * Get available capabilities and do the sanity check.
+ * Get available capabilities and do the validation check.
*
* @return reported available capabilities list, empty list if the value is unavailable.
*/
@@ -2070,7 +2070,7 @@
}
/**
- * Get max number of output raw streams and do the basic sanity check.
+ * Get max number of output raw streams and do the basic validation check.
*
* @return reported max number of raw output stream
*/
@@ -2083,7 +2083,7 @@
}
/**
- * Get max number of output processed streams and do the basic sanity check.
+ * Get max number of output processed streams and do the basic validation check.
*
* @return reported max number of processed output stream
*/
@@ -2096,7 +2096,7 @@
}
/**
- * Get max number of output stalling processed streams and do the basic sanity check.
+ * Get max number of output stalling processed streams and do the basic validation check.
*
* @return reported max number of stalling processed output stream
*/
@@ -2109,7 +2109,7 @@
}
/**
- * Get lens facing and do the sanity check
+ * Get lens facing and do the validation check
* @return lens facing, return default value (BACK) if value is unavailable.
*/
public int getLensFacingChecked() {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
index 31b7967..47caf0a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2CaptureRequestTest.java
@@ -309,7 +309,7 @@
private void changeExposure(CaptureRequest.Builder requestBuilder,
long expTime, int sensitivity) {
// Check if the max analog sensitivity is available and no larger than max sensitivity.
- // The max analog sensitivity is not actually used here. This is only an extra sanity check.
+ // The max analog sensitivity is not actually used here. This is only an extra check.
mStaticInfo.getMaxAnalogSensitivityChecked();
expTime = mStaticInfo.getExposureClampToRange(expTime);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index 6a4db57..dc8da48 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -985,7 +985,7 @@
}
/**
- * Validate video snapshot capture image object sanity and test.
+ * Validate video snapshot capture image object soundness and test.
*
* <p> Check for size, format and jpeg decoding</p>
*
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
index f7373f7..cbdcc36 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2StillCaptureTest.java
@@ -570,7 +570,7 @@
}
/**
- * Validate JPEG capture image object sanity and test.
+ * Validate JPEG capture image object soundness and test.
* <p>
* In addition to image object sanity, this function also does the decoding
* test, which is slower.
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 66637ef..5aaca43 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -43605,6 +43605,7 @@
package android.telecom {
public final class Call {
+ method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void answer(int);
method public void conference(android.telecom.Call);
method public void deflect(android.net.Uri);
@@ -43713,6 +43714,7 @@
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static String propertiesToString(int);
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 33554432; // 0x2000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
@@ -43742,6 +43744,7 @@
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -43819,6 +43822,7 @@
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
+ method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -43834,6 +43838,9 @@
method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState();
+ method public final boolean isRingbackRequested();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
+ method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
@@ -43842,6 +43849,7 @@
method public void onMerge(android.telecom.Connection);
method public void onMerge();
method public void onPlayDtmfTone(char);
+ method public void onReject();
method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone();
method public void onSwap();
@@ -43862,6 +43870,8 @@
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold();
+ method public final void setRingbackRequested(boolean);
+ method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int);
@@ -43898,6 +43908,7 @@
method public final boolean isRingbackRequested();
method public final void notifyConferenceMergeFailed();
method public void onAbort();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
@@ -43977,6 +43988,7 @@
field public static final int AUDIO_CODEC_GSM_HR = 10; // 0xa
field public static final int AUDIO_CODEC_NONE = 0; // 0x0
field public static final int AUDIO_CODEC_QCELP13K = 3; // 0x3
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 67108864; // 0x4000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
@@ -44020,6 +44032,7 @@
field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -44115,9 +44128,13 @@
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -44428,6 +44445,7 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
+ method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -44455,6 +44473,7 @@
method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
+ method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -44994,6 +45013,8 @@
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+ field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
+ field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
@@ -46066,12 +46087,13 @@
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
+ method @NonNull public android.telephony.SmsManager createForSubscriptionId(int);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method @NonNull public android.os.Bundle getCarrierConfigValues();
- method public static android.telephony.SmsManager getDefault();
+ method @Deprecated public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
- method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+ method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
method public int getSubscriptionId();
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index c1dbfb7..3c0b955 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -31,12 +31,25 @@
}
+package android.media {
+
+ public class AudioManager {
+ field public static final int FLAG_FROM_KEY = 4096; // 0x1000
+ }
+
+}
+
package android.os {
public class Binder implements android.os.IBinder {
method public final void markVintfStability();
}
+ public interface Parcelable {
+ field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
+ field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
+ }
+
public class StatsServiceManager {
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
index c7af8c8..d0776ae 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
@@ -40,18 +40,18 @@
*
* <p>IMPORTANT: The use or edit of this method requires a security review.
*
- * @param masterKey Master key from which to derive sub-keys.
+ * @param mainKey Main key from which to derive sub-keys.
* @param salt A randomly generated 256-bit byte string.
* @param data Arbitrary information that is bound to the derived key (i.e., used in its
* creation).
- * @return Raw derived key bytes = HKDF-SHA256(masterKey, salt, data).
+ * @return Raw derived key bytes = HKDF-SHA256(mainKey, salt, data).
* @throws InvalidKeyException If the salt can not be used as a valid key.
*/
- static byte[] hkdf(byte[] masterKey, byte[] salt, byte[] data) throws InvalidKeyException {
- Objects.requireNonNull(masterKey, "HKDF requires master key to be set.");
+ static byte[] hkdf(byte[] mainKey, byte[] salt, byte[] data) throws InvalidKeyException {
+ Objects.requireNonNull(mainKey, "HKDF requires main key to be set.");
Objects.requireNonNull(salt, "HKDF requires a salt.");
Objects.requireNonNull(data, "No data provided to HKDF.");
- return hkdfSha256Expand(hkdfSha256Extract(masterKey, salt), data);
+ return hkdfSha256Expand(hkdfSha256Extract(mainKey, salt), data);
}
private Hkdf() {}
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index cf967c0..039f2c0 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -24,12 +24,35 @@
<bool name="config_enableFullscreenUserSwitcher">true</bool>
- <!-- configure which system ui bars should be displayed -->
+ <!-- Configure which system bars should be displayed. -->
<bool name="config_enableTopNavigationBar">true</bool>
<bool name="config_enableLeftNavigationBar">false</bool>
<bool name="config_enableRightNavigationBar">false</bool>
<bool name="config_enableBottomNavigationBar">true</bool>
+ <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
+ <!-- STATUS_BAR = 0-->
+ <!-- NAVIGATION_BAR = 1-->
+ <!-- STATUS_BAR_EXTRA = 2-->
+ <!-- NAVIGATION_BAR_EXTRA = 3-->
+ <integer name="config_topSystemBarType">0</integer>
+ <integer name="config_leftSystemBarType">2</integer>
+ <integer name="config_rightSystemBarType">3</integer>
+ <integer name="config_bottomSystemBarType">1</integer>
+
+ <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
+ if both top bar and left bar are enabled, it creates an overlapping space in the upper left
+ corner), the system bar with the higher z-order takes the overlapping space and padding is
+ applied to the other bar.-->
+ <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
+ RuntimeException, since their placing order cannot be determined. Bars that do not overlap
+ are allowed to have the same z-order. -->
+ <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
+ <integer name="config_topSystemBarZOrder">1</integer>
+ <integer name="config_leftSystemBarZOrder">0</integer>
+ <integer name="config_rightSystemBarZOrder">0</integer>
+ <integer name="config_bottomSystemBarZOrder">10</integer>
+
<!-- Disable normal notification rendering; we handle that ourselves -->
<bool name="config_renderNotifications">false</bool>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 7b6dceb..995a3ec 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -134,9 +134,13 @@
}
@Singleton
- @Binds
- abstract DisplayImeController bindDisplayImeController(
- DisplaySystemBarsController displaySystemBarsController);
+ @Provides
+ static DisplayImeController provideDisplayImeController(Context context,
+ IWindowManager wmService, DisplayController displayController,
+ @Main Handler mainHandler, TransactionPool transactionPool) {
+ return new DisplaySystemBarsController.Builder(context, wmService, displayController,
+ mainHandler, transactionPool).build();
+ }
@Binds
abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 35b2080..9584850 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,12 +16,8 @@
package com.android.systemui.car.navigationbar;
-import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -30,13 +26,11 @@
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PixelFormat;
import android.inputmethodservice.InputMethodService;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Display;
-import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsetsController;
@@ -47,7 +41,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedListener;
@@ -76,7 +69,6 @@
/** Navigation bars customized for the automotive use case. */
public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
-
private final Resources mResources;
private final CarNavigationBarController mCarNavigationBarController;
private final SysuiDarkIconDispatcher mStatusBarIconController;
@@ -93,6 +85,7 @@
private final Lazy<StatusBarIconController> mIconControllerLazy;
private final int mDisplayId;
+ private final SystemBarConfigs mSystemBarConfigs;
private StatusBarSignalPolicy mSignalPolicy;
private ActivityManagerWrapper mActivityManagerWrapper;
@@ -141,7 +134,8 @@
IStatusBarService barService,
Lazy<KeyguardStateController> keyguardStateControllerLazy,
Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
- Lazy<StatusBarIconController> iconControllerLazy
+ Lazy<StatusBarIconController> iconControllerLazy,
+ SystemBarConfigs systemBarConfigs
) {
super(context);
mResources = resources;
@@ -158,6 +152,7 @@
mKeyguardStateControllerLazy = keyguardStateControllerLazy;
mIconPolicyLazy = iconPolicyLazy;
mIconControllerLazy = iconControllerLazy;
+ mSystemBarConfigs = systemBarConfigs;
mDisplayId = context.getDisplayId();
}
@@ -344,103 +339,63 @@
private void buildNavBarContent() {
mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
if (mTopNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
mTopNavigationBarWindow.addView(mTopNavigationBarView);
}
mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
if (mBottomNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
}
mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
if (mLeftNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
}
mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
if (mRightNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
mRightNavigationBarWindow.addView(mRightNavigationBarView);
}
}
private void attachNavBarWindows() {
- if (mTopNavigationBarWindow != null) {
- int height = mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- height,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("TopCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
- lp.setFitInsetsTypes(0);
- lp.windowAnimations = 0;
- lp.gravity = Gravity.TOP;
- mWindowManager.addView(mTopNavigationBarWindow, lp);
- }
+ mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
+ }
- if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
- mBottomNavBarVisible = true;
- int height = mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height);
+ private void attachNavBarBySide(int side) {
+ switch(side) {
+ case SystemBarConfigs.TOP:
+ if (mTopNavigationBarWindow != null) {
+ mWindowManager.addView(mTopNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));
+ }
+ break;
+ case SystemBarConfigs.BOTTOM:
+ if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
+ mBottomNavBarVisible = true;
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- height,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("BottomCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
- lp.windowAnimations = 0;
- lp.gravity = Gravity.BOTTOM;
- mWindowManager.addView(mBottomNavigationBarWindow, lp);
- }
-
- if (mLeftNavigationBarWindow != null) {
- int width = mResources.getDimensionPixelSize(
- R.dimen.car_left_navigation_bar_width);
- WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
- width, ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- leftlp.setTitle("LeftCarNavigationBar");
- leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
- leftlp.setFitInsetsTypes(0);
- leftlp.windowAnimations = 0;
- leftlp.gravity = Gravity.LEFT;
- mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
- }
-
- if (mRightNavigationBarWindow != null) {
- int width = mResources.getDimensionPixelSize(
- R.dimen.car_right_navigation_bar_width);
- WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
- width, ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- rightlp.setTitle("RightCarNavigationBar");
- rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR};
- rightlp.setFitInsetsTypes(0);
- rightlp.windowAnimations = 0;
- rightlp.gravity = Gravity.RIGHT;
- mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+ mWindowManager.addView(mBottomNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));
+ }
+ break;
+ case SystemBarConfigs.LEFT:
+ if (mLeftNavigationBarWindow != null) {
+ mWindowManager.addView(mLeftNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));
+ }
+ break;
+ case SystemBarConfigs.RIGHT:
+ if (mRightNavigationBarWindow != null) {
+ mWindowManager.addView(mRightNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));
+ }
+ break;
+ default:
+ return;
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index ca780ae..fe26040 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -22,7 +22,6 @@
import androidx.annotation.Nullable;
-import com.android.systemui.R;
import com.android.systemui.car.hvac.HvacController;
import javax.inject.Inject;
@@ -61,7 +60,8 @@
NavigationBarViewFactory navigationBarViewFactory,
ButtonSelectionStateController buttonSelectionStateController,
Lazy<HvacController> hvacControllerLazy,
- ButtonRoleHolderController buttonRoleHolderController) {
+ ButtonRoleHolderController buttonRoleHolderController,
+ SystemBarConfigs systemBarConfigs) {
mContext = context;
mNavigationBarViewFactory = navigationBarViewFactory;
mButtonSelectionStateController = buttonSelectionStateController;
@@ -69,10 +69,10 @@
mButtonRoleHolderController = buttonRoleHolderController;
// Read configuration.
- mShowTop = mContext.getResources().getBoolean(R.bool.config_enableTopNavigationBar);
- mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
- mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
- mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+ mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP);
+ mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM);
+ mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT);
+ mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT);
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 0ced402..ab401bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,14 +16,10 @@
package com.android.systemui.car.navigationbar;
-import static android.view.WindowInsets.Type.systemBars;
-
import android.content.Context;
-import android.graphics.Insets;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.view.WindowInsets;
import android.widget.LinearLayout;
import com.android.systemui.Dependency;
@@ -80,30 +76,6 @@
setFocusable(false);
}
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
- applyMargins(windowInsets.getInsets(systemBars()));
- return windowInsets;
- }
-
- private void applyMargins(Insets insets) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child.getLayoutParams() instanceof LayoutParams) {
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
- || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
- lp.rightMargin = insets.right;
- lp.leftMargin = insets.left;
- lp.topMargin = insets.top;
- lp.bottomMargin = insets.bottom;
- child.requestLayout();
- }
- }
- }
- }
-
// Used to forward touch events even if the touch was initiated from a child component
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
new file mode 100644
index 0000000..3527bf9
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -0,0 +1,380 @@
+/*
+ * 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.car.navigationbar;
+
+import android.annotation.IntDef;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.InsetsState;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the
+ * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration.
+ */
+@Singleton
+public class SystemBarConfigs {
+
+ private static final String TAG = SystemBarConfigs.class.getSimpleName();
+ // The z-order from which system bars will start to appear on top of HUN's.
+ private static final int HUN_ZORDER = 10;
+
+ @IntDef(value = {TOP, BOTTOM, LEFT, RIGHT})
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ private @interface SystemBarSide {
+ }
+
+ public static final int TOP = 0;
+ public static final int BOTTOM = 1;
+ public static final int LEFT = 2;
+ public static final int RIGHT = 3;
+
+ /*
+ NOTE: The elements' order in the map below must be preserved as-is since the correct
+ corresponding values are obtained by the index.
+ */
+ private static final int[] BAR_TYPE_MAP = {
+ InsetsState.ITYPE_STATUS_BAR,
+ InsetsState.ITYPE_NAVIGATION_BAR,
+ InsetsState.ITYPE_CLIMATE_BAR,
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+ };
+
+ private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>();
+ private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>();
+ private static final Map<@SystemBarSide Integer, Integer> BAR_GESTURE_MAP = new ArrayMap<>();
+
+ private final Resources mResources;
+ private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap =
+ new ArrayMap<>();
+ private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>();
+
+ private boolean mTopNavBarEnabled;
+ private boolean mBottomNavBarEnabled;
+ private boolean mLeftNavBarEnabled;
+ private boolean mRightNavBarEnabled;
+
+ @Inject
+ public SystemBarConfigs(@Main Resources resources) {
+ mResources = resources;
+
+ populateMaps();
+ readConfigs();
+ checkEnabledBarsHaveUniqueBarTypes();
+ setInsetPaddingsForOverlappingCorners();
+ sortSystemBarSidesByZOrder();
+ }
+
+ protected WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) {
+ return mSystemBarConfigMap.get(side) != null
+ ? mSystemBarConfigMap.get(side).getLayoutParams() : null;
+ }
+
+ protected boolean getEnabledStatusBySide(@SystemBarSide int side) {
+ switch (side) {
+ case TOP:
+ return mTopNavBarEnabled;
+ case BOTTOM:
+ return mBottomNavBarEnabled;
+ case LEFT:
+ return mLeftNavBarEnabled;
+ case RIGHT:
+ return mRightNavBarEnabled;
+ default:
+ return false;
+ }
+ }
+
+ protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
+ int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
+ view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
+ }
+
+ protected List<Integer> getSystemBarSidesByZOrder() {
+ return mSystemBarSidesByZOrder;
+ }
+
+ @VisibleForTesting
+ protected static int getHunZOrder() {
+ return HUN_ZORDER;
+ }
+
+ private static void populateMaps() {
+ BAR_GRAVITY_MAP.put(TOP, Gravity.TOP);
+ BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM);
+ BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT);
+ BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT);
+
+ BAR_TITLE_MAP.put(TOP, "TopCarSystemBar");
+ BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar");
+ BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");
+ BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");
+
+ BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_GESTURES);
+ BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_GESTURES);
+ BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_GESTURES);
+ BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_GESTURES);
+ }
+
+ private void readConfigs() {
+ mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopNavigationBar);
+ mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomNavigationBar);
+ mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftNavigationBar);
+ mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightNavigationBar);
+
+ if (mTopNavBarEnabled) {
+ SystemBarConfig topBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(TOP)
+ .setGirth(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height))
+ .setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(TOP, topBarConfig);
+ }
+
+ if (mBottomNavBarEnabled) {
+ SystemBarConfig bottomBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(BOTTOM)
+ .setGirth(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height))
+ .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
+ .setZOrder(
+ mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(BOTTOM, bottomBarConfig);
+ }
+
+ if (mLeftNavBarEnabled) {
+ SystemBarConfig leftBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(LEFT)
+ .setGirth(mResources.getDimensionPixelSize(
+ R.dimen.car_left_navigation_bar_width))
+ .setBarType(mResources.getInteger(R.integer.config_leftSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(LEFT, leftBarConfig);
+ }
+
+ if (mRightNavBarEnabled) {
+ SystemBarConfig rightBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(RIGHT)
+ .setGirth(mResources.getDimensionPixelSize(
+ R.dimen.car_right_navigation_bar_width))
+ .setBarType(mResources.getInteger(R.integer.config_rightSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(RIGHT, rightBarConfig);
+ }
+ }
+
+ private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException {
+ Set<Integer> barTypesUsed = new ArraySet<>();
+ int enabledNavBarCount = mSystemBarConfigMap.size();
+
+ for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) {
+ barTypesUsed.add(systemBarConfig.getBarType());
+ }
+
+ // The number of bar types used cannot be fewer than that of enabled system bars.
+ if (barTypesUsed.size() < enabledNavBarCount) {
+ throw new RuntimeException("Each enabled system bar must have a unique bar type. Check "
+ + "the configuration in config.xml");
+ }
+ }
+
+ private void setInsetPaddingsForOverlappingCorners() {
+ setInsetPaddingForOverlappingCorner(TOP, LEFT);
+ setInsetPaddingForOverlappingCorner(TOP, RIGHT);
+ setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
+ setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
+ }
+
+ private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
+ @SystemBarSide int verticalSide) {
+
+ if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
+ Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
+ + "vertical sides were not provided correctly.");
+ return;
+ }
+
+ SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
+ SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
+
+ if (verticalBarConfig != null && horizontalBarConfig != null) {
+ int horizontalBarZOrder = horizontalBarConfig.getZOrder();
+ int horizontalBarGirth = horizontalBarConfig.getGirth();
+ int verticalBarZOrder = verticalBarConfig.getZOrder();
+ int verticalBarGirth = verticalBarConfig.getGirth();
+
+ if (horizontalBarZOrder > verticalBarZOrder) {
+ verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth);
+ } else if (horizontalBarZOrder < verticalBarZOrder) {
+ horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth);
+ } else {
+ throw new RuntimeException(
+ BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
+ + " have the same Z-Order, and so their placing order cannot be "
+ + "determined. Determine which bar should be placed on top of the "
+ + "other bar and change the Z-order in config.xml accordingly."
+ );
+ }
+ }
+ }
+
+ private void sortSystemBarSidesByZOrder() {
+ List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
+
+ systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
+ @Override
+ public int compare(SystemBarConfig o1, SystemBarConfig o2) {
+ return o1.getZOrder() - o2.getZOrder();
+ }
+ });
+
+ systemBarsByZOrder.forEach(systemBarConfig -> {
+ mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
+ });
+ }
+
+ private static boolean isHorizontalBar(@SystemBarSide int side) {
+ return side == TOP || side == BOTTOM;
+ }
+
+ private static boolean isVerticalBar(@SystemBarSide int side) {
+ return side == LEFT || side == RIGHT;
+ }
+
+ private static final class SystemBarConfig {
+ private final int mSide;
+ private final int mBarType;
+ private final int mGirth;
+ private final int mZOrder;
+
+ private int[] mPaddings = new int[]{0, 0, 0, 0};
+
+ private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder) {
+ mSide = side;
+ mBarType = barType;
+ mGirth = girth;
+ mZOrder = zOrder;
+ }
+
+ private int getSide() {
+ return mSide;
+ }
+
+ private int getBarType() {
+ return mBarType;
+ }
+
+ private int getGirth() {
+ return mGirth;
+ }
+
+ private int getZOrder() {
+ return mZOrder;
+ }
+
+ private int[] getPaddings() {
+ return mPaddings;
+ }
+
+ private WindowManager.LayoutParams getLayoutParams() {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth,
+ isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT,
+ mapZOrderToBarType(mZOrder),
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle(BAR_TITLE_MAP.get(mSide));
+ lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)};
+ lp.setFitInsetsTypes(0);
+ lp.windowAnimations = 0;
+ lp.gravity = BAR_GRAVITY_MAP.get(mSide);
+ return lp;
+ }
+
+ private int mapZOrderToBarType(int zOrder) {
+ return zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
+ : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
+ }
+
+ private void setPaddingBySide(@SystemBarSide int side, int padding) {
+ mPaddings[side] = padding;
+ }
+ }
+
+ private static final class SystemBarConfigBuilder {
+ private int mSide;
+ private int mBarType;
+ private int mGirth;
+ private int mZOrder;
+
+ private SystemBarConfigBuilder setSide(@SystemBarSide int side) {
+ mSide = side;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setBarType(int type) {
+ mBarType = type;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setGirth(int girth) {
+ mGirth = girth;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setZOrder(int zOrder) {
+ mZOrder = zOrder;
+ return this;
+ }
+
+ private SystemBarConfig build() {
+ return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index d0a2aeb..5bd8797 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -33,6 +33,7 @@
import android.car.user.UserCreationResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.UserHelper;
+import android.car.util.concurrent.AsyncFuture;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -60,7 +61,6 @@
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.UserIcons;
import com.android.systemui.R;
@@ -449,7 +449,7 @@
*/
@Nullable
public UserInfo createNewOrFindExistingGuest(Context context) {
- AndroidFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName);
+ AsyncFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName);
// CreateGuest will return null if a guest already exists.
UserInfo newGuest = getUserInfo(future);
if (newGuest != null) {
@@ -482,7 +482,7 @@
}
@Nullable
- private UserInfo getUserInfo(AndroidFuture<UserCreationResult> future) {
+ private UserInfo getUserInfo(AsyncFuture<UserCreationResult> future) {
UserCreationResult userCreationResult;
try {
userCreationResult = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -504,7 +504,7 @@
}
private boolean switchUser(@UserIdInt int userId) {
- AndroidFuture<UserSwitchResult> userSwitchResultFuture =
+ AsyncFuture<UserSwitchResult> userSwitchResultFuture =
mCarUserManager.switchUser(userId);
UserSwitchResult userSwitchResult;
try {
@@ -531,7 +531,7 @@
@Override
protected UserInfo doInBackground(String... userNames) {
- AndroidFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0],
+ AsyncFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0],
/* flags= */ 0);
try {
UserInfo user = getUserInfo(future);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
index aea6914..7db2823 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
@@ -16,12 +16,12 @@
package com.android.systemui.car.userswitcher;
-import android.app.ActivityManager;
import android.car.Car;
import android.car.user.CarUserManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.window.OverlayViewMediator;
@@ -36,13 +36,16 @@
private static final String TAG = "UserSwitchTransitionViewMediator";
private final CarServiceProvider mCarServiceProvider;
+ private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
@Inject
public UserSwitchTransitionViewMediator(
CarServiceProvider carServiceProvider,
+ CarDeviceProvisionedController carDeviceProvisionedController,
UserSwitchTransitionViewController userSwitchTransitionViewController) {
mCarServiceProvider = carServiceProvider;
+ mCarDeviceProvisionedController = carDeviceProvisionedController;
mUserSwitchTransitionViewController = userSwitchTransitionViewController;
}
@@ -74,7 +77,7 @@
@VisibleForTesting
void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) {
if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING
- && ActivityManager.getCurrentUser() == event.getUserId()) {
+ && mCarDeviceProvisionedController.getCurrentUser() == event.getUserId()) {
mUserSwitchTransitionViewController.handleShow(event.getUserId());
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index 5c80202..e493c97 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -36,25 +36,20 @@
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.TransactionPool;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
/**
* Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to
* give system bar control to SystemUI.
* {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller
* takes control or not.
*/
-@Singleton
public class DisplaySystemBarsController extends DisplayImeController {
private static final String TAG = "DisplaySystemBarsController";
- private SparseArray<PerDisplay> mPerDisplaySparseArray;
private final Context mContext;
+ private SparseArray<PerDisplay> mPerDisplaySparseArray;
- @Inject
- public DisplaySystemBarsController(
+ private DisplaySystemBarsController(
Context context,
IWindowManager wmService,
DisplayController displayController,
@@ -172,4 +167,33 @@
}
}
}
+
+ /** Builds {@link DisplaySystemBarsController} instance. */
+ public static class Builder {
+ private Context mContext;
+ private IWindowManager mWmService;
+ private DisplayController mDisplayController;
+ private Handler mHandler;
+ private TransactionPool mTransactionPool;
+
+ public Builder(Context context, IWindowManager wmService,
+ DisplayController displayController, Handler handler,
+ TransactionPool transactionPool) {
+ mContext = context;
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mHandler = handler;
+ mTransactionPool = transactionPool;
+ }
+
+ /** Builds and initializes {@link DisplaySystemBarsController} instance. */
+ public DisplaySystemBarsController build() {
+ DisplaySystemBarsController displaySystemBarsController =
+ new DisplaySystemBarsController(
+ mContext, mWmService, mDisplayController, mHandler, mTransactionPool);
+ // Separates startMonitorDisplays from constructor to prevent circular init issue.
+ displaySystemBarsController.startMonitorDisplays();
+ return displaySystemBarsController;
+ }
+ }
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index dec8b8e..0b164a2 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -73,7 +73,8 @@
private CarNavigationBarController createNavigationBarController() {
return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
mButtonSelectionStateController, () -> mHvacController,
- mButtonRoleHolderController);
+ mButtonRoleHolderController,
+ new SystemBarConfigs(mTestableResources.getResources()));
}
@Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index d9edfa96..2b5af71 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -142,7 +142,7 @@
mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor,
mBarService, () -> mKeyguardStateController, () -> mIconPolicy,
- () -> mIconController);
+ () -> mIconController, new SystemBarConfigs(mTestableResources.getResources()));
}
@Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
new file mode 100644
index 0000000..8b15899
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.car.navigationbar;
+
+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.Mockito.when;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class SystemBarConfigsTest extends SysuiTestCase {
+
+ private SystemBarConfigs mSystemBarConfigs;
+ @Mock
+ private Resources mResources;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ setDefaultValidConfig();
+ }
+
+ @Test
+ public void onInit_allSystemBarsEnabled_eachHasUniqueBarTypes_doesNotThrowException() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void onInit_allSystemBarsEnabled_twoBarsHaveDuplicateType_throwsRuntimeException() {
+ when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(0);
+
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test
+ public void onInit_allSystemBarsEnabled_systemBarSidesSortedByZOrder() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ List<Integer> actualOrder = mSystemBarConfigs.getSystemBarSidesByZOrder();
+ List<Integer> expectedOrder = new ArrayList<>();
+ expectedOrder.add(SystemBarConfigs.LEFT);
+ expectedOrder.add(SystemBarConfigs.RIGHT);
+ expectedOrder.add(SystemBarConfigs.TOP);
+ expectedOrder.add(SystemBarConfigs.BOTTOM);
+
+ assertTrue(actualOrder.equals(expectedOrder));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void onInit_intersectingBarsHaveSameZOrder_throwsRuntimeException() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(33);
+ when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(33);
+
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test
+ public void getTopSystemBarLayoutParams_topBarEnabled_returnsTopSystemBarLayoutParams() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertNotNull(lp);
+ }
+
+ @Test
+ public void getTopSystemBarLayoutParams_topBarNotEnabled_returnsNull() {
+ when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertNull(lp);
+ }
+
+ @Test
+ public void topSystemBarHasHigherZOrderThanHuns_topSystemBarIsNavigationBarPanelType() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+ SystemBarConfigs.getHunZOrder() + 1);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertEquals(lp.type, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL);
+ }
+
+ @Test
+ public void topSystemBarHasLowerZOrderThanHuns_topSystemBarIsStatusBarAdditionalType() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+ SystemBarConfigs.getHunZOrder() - 1);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
+ }
+
+ // Set valid config where all system bars are enabled.
+ private void setDefaultValidConfig() {
+ when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableBottomNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableLeftNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
+
+ when(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height)).thenReturn(100);
+ when(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
+ 100);
+ when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
+ 100);
+
+ when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
+ when(mResources.getInteger(R.integer.config_leftSystemBarType)).thenReturn(2);
+ when(mResources.getInteger(R.integer.config_rightSystemBarType)).thenReturn(3);
+
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(5);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).thenReturn(10);
+ when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(2);
+ when(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).thenReturn(3);
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
index 20576e9..67f222b 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
@@ -220,7 +220,7 @@
verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1);
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display2);
+ verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display3);
verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display1);
verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
index de6feb6..7aeffce 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.car.userswitcher;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -24,6 +25,8 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.CarSystemUiTest;
@@ -37,13 +40,15 @@
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
-public class UserSwitchTransitionViewMediatorTest {
+public class UserSwitchTransitionViewMediatorTest extends SysuiTestCase {
private static final int TEST_USER = 100;
private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator;
@Mock
private CarServiceProvider mCarServiceProvider;
@Mock
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ @Mock
private UserSwitchTransitionViewController mUserSwitchTransitionViewController;
@Mock
private CarUserManager.UserLifecycleEvent mUserLifecycleEvent;
@@ -53,21 +58,35 @@
MockitoAnnotations.initMocks(this);
mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator(
- mCarServiceProvider, mUserSwitchTransitionViewController);
-
+ mCarServiceProvider, mCarDeviceProvisionedController,
+ mUserSwitchTransitionViewController);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER);
}
@Test
- public void onUserLifecycleEvent_userStarting_callsHandleShow() {
+ public void onUserLifecycleEvent_userStarting_isCurrentUser_callsHandleShow() {
when(mUserLifecycleEvent.getEventType()).thenReturn(
CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
+
mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
verify(mUserSwitchTransitionViewController).handleShow(TEST_USER);
}
@Test
+ public void onUserLifecycleEvent_userStarting_isNotCurrentUser_doesNotCallHandleShow() {
+ when(mUserLifecycleEvent.getEventType()).thenReturn(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
+ when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER + 1);
+
+ mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
+
+ verify(mUserSwitchTransitionViewController, never()).handleShow(TEST_USER);
+ }
+
+ @Test
public void onUserLifecycleEvent_userSwitching_callsHandleHide() {
when(mUserLifecycleEvent.getEventType()).thenReturn(
CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
index 391f75e..b65578d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
@@ -64,13 +64,13 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new DisplaySystemBarsController(
+ mController = new DisplaySystemBarsController.Builder(
mContext,
mIWindowManager,
mDisplayController,
mHandler,
mTransactionPool
- );
+ ).build();
}
@Test
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 1b5062e..01d7682 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -42,10 +42,10 @@
<string name="connected_via_app" msgid="3532267661404276584">"Падключана праз праграму \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Даступна праз %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Націсніце, каб зарэгістравацца"</string>
- <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Не падключана да інтэрнэту"</string>
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Няма падключэння да інтэрнэту"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Абмежаваныя магчымасці падключэння"</string>
- <string name="wifi_status_no_internet" msgid="3799933875988829048">"Не падключана да інтэрнэту"</string>
+ <string name="wifi_status_no_internet" msgid="3799933875988829048">"Няма падключэння да інтэрнэту"</string>
<string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Трэба выканаць уваход"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Пункт доступу часова заняты"</string>
<string name="connected_via_carrier" msgid="1968057009076191514">"Падключана праз %1$s"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8e8368f..03161d0 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -659,9 +659,6 @@
<!-- Setting Checkbox title for enabling Bluetooth Gabeldorsche. [CHAR LIMIT=40] -->
<string name="bluetooth_enable_gabeldorsche">Enable Gabeldorsche</string>
- <!-- Setting Checkbox title for enabling Enhanced Connectivity [CHAR LIMIT=80] -->
- <string name="enhanced_connectivity">Enhanced Connectivity</string>
-
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
<string name="bluetooth_select_avrcp_version_string">Bluetooth AVRCP Version</string>
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ef3bdbc9..fa06e14 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -761,8 +761,8 @@
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
dumpSetting(s, p,
- Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
- GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
+ GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST);
dumpSetting(s, p,
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
GlobalSettingsProto.Gpu.SHOW_ANGLE_IN_USE_DIALOG);
@@ -785,14 +785,14 @@
Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_OUT_APPS);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLIST);
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLIST);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_WHITELIST,
- GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
+ Settings.Global.GAME_DRIVER_ALLOWLIST,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_ALLOWLIST);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_BLACKLISTS,
- GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLISTS);
dumpSetting(s, p,
Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES,
GlobalSettingsProto.Gpu.GAME_DRIVER_SPHAL_LIBRARIES);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
index 6e5b889..66aa7ba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
@@ -35,19 +35,17 @@
public class WriteFallbackSettingsFilesJobService extends JobService {
@Override
public boolean onStartJob(final JobParameters params) {
- switch (params.getJobId()) {
- case WRITE_FALLBACK_SETTINGS_FILES_JOB_ID:
- final List<String> settingsFiles = new ArrayList<>();
- settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SECURE, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SSAID, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, ""));
- SettingsProvider.writeFallBackSettingsFiles(settingsFiles);
- return true;
- default:
- return false;
+ if (params.getJobId() != WRITE_FALLBACK_SETTINGS_FILES_JOB_ID) {
+ return false;
}
+ final List<String> settingsFiles = new ArrayList<>();
+ settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SECURE, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SSAID, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, ""));
+ SettingsProvider.writeFallBackSettingsFiles(settingsFiles);
+ return false;
}
@Override
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 6914f0a..24f8104 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -270,7 +270,6 @@
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
- Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
Settings.Global.ERROR_LOGCAT_PREFIX,
@@ -297,6 +296,7 @@
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
+ Settings.Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
@@ -502,14 +502,14 @@
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
- Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST,
Settings.Global.GAME_DRIVER_ALL_APPS,
Settings.Global.GAME_DRIVER_OPT_IN_APPS,
Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS,
Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
- Settings.Global.GAME_DRIVER_BLACKLISTS,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- Settings.Global.GAME_DRIVER_WHITELIST,
+ Settings.Global.GAME_DRIVER_DENYLISTS,
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ Settings.Global.GAME_DRIVER_ALLOWLIST,
Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES,
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
Settings.Global.GPU_DEBUG_LAYER_APP,
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
index ff26710..176035f 100644
--- a/packages/SimAppDialog/Android.bp
+++ b/packages/SimAppDialog/Android.bp
@@ -4,7 +4,6 @@
srcs: ["src/**/*.java"],
platform_apis: true,
- certificate: "platform",
static_libs: [
"androidx.legacy_legacy-support-v4",
diff --git a/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png
new file mode 100644
index 0000000..6c1f1cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
new file mode 100644
index 0000000..6983c3b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
new file mode 100644
index 0000000..3ff692f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
new file mode 100644
index 0000000..75723fb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
new file mode 100644
index 0000000..173abed
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e48fe65..308fd88 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Instellings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Het dit"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Stort SysUI-hoop"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> gebruik tans jou <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programme gebruik tans jou <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ligging"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors is af"</string>
<string name="device_services" msgid="1549944177856658705">"Toesteldienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 300ca0e..f2bf577 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ቅንብሮች"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ገባኝ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Heap አራግፍ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> የእርስዎን <xliff:g id="TYPES_LIST">%2$s</xliff:g> እየተጠቀመ ነው።"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"መተግበሪያዎች የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> እየተጠቀሙ ነው።"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"፣ "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" እና "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ካሜራ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"አካባቢ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ማይክሮፎን"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ዳሳሾች ጠፍተዋል"</string>
<string name="device_services" msgid="1549944177856658705">"የመሣሪያ አገልግሎቶች"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7f2a405..36280e7 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1005,6 +1005,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"الإعدادات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"حسنًا"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"تفريغ ذاكرة SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"التطبيق <xliff:g id="APP">%1$s</xliff:g> يستخدم <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"تستخدم التطبيقات <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"الكاميرا"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"الموقع"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"الميكروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"إيقاف أجهزة الاستشعار"</string>
<string name="device_services" msgid="1549944177856658705">"خدمات الأجهزة"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0345af0..a4cc17b 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ছেটিংবোৰ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"বুজি পালোঁ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"এপ্লিকেশ্বনসমূহে আপোনাৰ <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" আৰু "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"কেমেৰা"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ছেন্সৰ অফ হৈ আছে"</string>
<string name="device_services" msgid="1549944177856658705">"ডিভাইচ সেৱা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index d0025306..9443ba8 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ayarlar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Anladım"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="TYPES_LIST">%2$s</xliff:g> tətbiqlərindən istifadə edir."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Tətbiqlər <xliff:g id="TYPES_LIST">%s</xliff:g> istifadə edir."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" və "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"məkan"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorlar deaktivdir"</string>
<string name="device_services" msgid="1549944177856658705">"Cihaz Xidmətləri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 5cca958..5b8c445 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Podešavanja"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Važi"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> koristi <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge za uređaje"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 956ef47..6ee51682 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -919,7 +919,7 @@
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Закрыць хуткія налады."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Будзільнік пастаўлены."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Вы ўвайшлі як <xliff:g id="ID_1">%s</xliff:g>"</string>
- <string name="data_connection_no_internet" msgid="691058178914184544">"Не падключана да інтэрнэту"</string>
+ <string name="data_connection_no_internet" msgid="691058178914184544">"Няма падключэння да інтэрнэту"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Паказаць падрабязную інфармацыю."</string>
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"Прычына недаступнасці: <xliff:g id="REASON">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Налады"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Зразумела"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" выкарыстоўвае: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Праграмы выкарыстоўваюць: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"геалакацыя"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"мікрафон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчыкі выкл."</string>
<string name="device_services" msgid="1549944177856658705">"Сэрвісы прылады"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d0836e4..c7bb3d0 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Настройки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Разбрах"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> използва <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Някои приложения използват <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камерата"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"местополож."</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофона"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензорите са изключени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуги за устройството"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index a584955..42e7523a 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"সেটিংস"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"বুঝেছি"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> আপনার <xliff:g id="TYPES_LIST">%2$s</xliff:g> ব্যবহার করছে।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"অ্যাপ্লিকেশনগুলি আপনার <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যবহার করছে।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" এবং "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ক্যামেরা"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"লোকেশন"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্রোফোন"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"সেন্সর বন্ধ"</string>
<string name="device_services" msgid="1549944177856658705">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4c872d2..16a1aa6 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Postavke"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Razumijem"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> koristi <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7267c31b1..fdcec98 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuració"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entesos"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Aboca espai de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> està fent servir el següent: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"càmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicació"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micròfon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors desactivats"</string>
<string name="device_services" msgid="1549944177856658705">"Serveis per a dispositius"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 29b5281..ab3b4fb 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavení"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Rozumím"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikace <xliff:g id="APP">%1$s</xliff:g> využívá tato oprávnění: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikace využívají tato oprávnění: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzory jsou vypnuty"</string>
<string name="device_services" msgid="1549944177856658705">"Služby zařízení"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index dff770d..0fc9b94 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Indstillinger"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Gem SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> anvender enhedens <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"placering"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Deaktiver sensorer"</string>
<string name="device_services" msgid="1549944177856658705">"Enhedstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 52275fc..a6b137a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Einstellungen"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> verwendet gerade Folgendes: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps verwenden gerade Folgendes: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" und "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"Kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"Standort"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"Mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensoren aus"</string>
<string name="device_services" msgid="1549944177856658705">"Gerätedienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bf4c619..bdd19a1 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ρυθμίσεις"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Το κατάλαβα"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Στιγμ. μνήμης SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> χρησιμοποιεί τις λειτουργίες <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Οι εφαρμογές χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" και "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"κάμερα"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"τοποθεσία"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"μικρόφωνο"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Αισθητήρες ανενεργοί"</string>
<string name="device_services" msgid="1549944177856658705">"Υπηρεσίες συσκευής"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index acb8111..68a8d30 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e3bad1f..e9856af 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index acb8111..68a8d30 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index acb8111..68a8d30 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 25ec6c3..eacef26 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Got it"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 01bed10..94a464b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuración"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entendido"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está usando tu <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Se desactivaron los sensores"</string>
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 67678d2..0e7d376e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ajustes"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entendido"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está usando tu <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que usan tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desactivados"</string>
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index a46fa49..fc9c73b 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Seaded"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Selge"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> kasutab järgmisi: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Rakendused kasutavad järgmisi: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kaamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"asukoht"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Andurid on välja lülitatud"</string>
<string name="device_services" msgid="1549944177856658705">"Seadme teenused"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 19fc4f5..041beab 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ezarpenak"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ados"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="TYPES_LIST">%2$s</xliff:g> erabiltzen ari da."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikazio batzuk <xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari dira."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" eta "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"kokapena"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonoa"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sentsoreak desaktibatuta daude"</string>
<string name="device_services" msgid="1549944177856658705">"Gailuetarako zerbitzuak"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b8c8793..05e076f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"تنظیمات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"متوجه شدم"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> از <xliff:g id="TYPES_LIST">%2$s</xliff:g> شما استفاده میکند."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"برنامهها از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده میکنند."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"دوربین"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"مکان"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"میکروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"حسگرها خاموش است"</string>
<string name="device_services" msgid="1549944177856658705">"سرویسهای دستگاه"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 44a66c3..4fccaac 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Asetukset"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Selvä"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Luo SysUI-keon vedos"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> käyttää ominaisuuksia (<xliff:g id="TYPES_LIST">%2$s</xliff:g>)."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> ovat sovellusten käytössä."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"sijainti"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Anturit pois päältä"</string>
<string name="device_services" msgid="1549944177856658705">"Laitepalvelut"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 15cf6eb..4e2074c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Paramètres"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> utilise votre <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Capteurs désactivés"</string>
<string name="device_services" msgid="1549944177856658705">"Services de l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 784186b..fedec56 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Paramètres"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> utilise votre <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micro"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Capteurs désactivés"</string>
<string name="device_services" msgid="1549944177856658705">"Services pour l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
@@ -1021,9 +1028,9 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Fenêtre des commandes d\'agrandissement"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Commandes de contrôle des appareils"</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 de contrôle des appareils"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Appuyez de manière prolongée sur le bouton Marche/Arrêt pour accéder aux commandes"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1046,7 +1053,7 @@
<string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossible de charger les commandes. Vérifiez l\'application <xliff:g id="APP">%s</xliff:g> pour vous assurer que les paramètres n\'ont pas changé."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"Commandes compatibles indisponibles"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de contrôle des appareils"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index c732c7b..c1b9024 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuración"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"De acordo"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Baleirado mem. SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está utilizando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"a cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"a localiz."</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"o micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Desactivar sensores"</string>
<string name="device_services" msgid="1549944177856658705">"Servizos do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5d3d3af..9c2f717 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"સેટિંગ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"સમજાઈ ગયું"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ઍપ તમારા <xliff:g id="TYPES_LIST">%2$s</xliff:g>નો ઉપયોગ કરી રહી છે."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ઍપ્લિકેશન તમારા <xliff:g id="TYPES_LIST">%s</xliff:g>નો ઉપયોગ કરી રહી છે."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" અને "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"કૅમેરા"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"સ્થાન"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"માઇક્રોફોન"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"સેન્સર બંધ છે"</string>
<string name="device_services" msgid="1549944177856658705">"ડિવાઇસ સેવાઓ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f6bc4cd..cc2faa2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -987,6 +987,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिंग"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ठीक है"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> आपकी <xliff:g id="TYPES_LIST">%2$s</xliff:g> का इस्तेमाल कर रहा है."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ऐप्लिकेशन आपकी <xliff:g id="TYPES_LIST">%s</xliff:g> का इस्तेमाल कर रहे हैं."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" और "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"कैमरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेंसर बंद हैं"</string>
<string name="device_services" msgid="1549944177856658705">"डिवाइस सेवाएं"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bfd5aa0..90251995 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Postavke"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Shvaćam"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji mem. SysUI-a"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> upotrebljava <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c8f4a46..689d869 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Beállítások"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Értem"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI-memória-kiírás"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"A(z) <xliff:g id="APP">%1$s</xliff:g> használja a következőket: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Több alkalmazás használja a következőket: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" és "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"helyadatok"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Érzékelők kikapcsolva"</string>
<string name="device_services" msgid="1549944177856658705">"Eszközszolgáltatások"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 5328618..a574f26 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -916,7 +916,7 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Խմբագրել կարգավորումների հերթականությունը:"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել է տաքանալու պատճառով"</string>
+ <string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել էր տաքանալու պատճառով"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"Հեռախոսն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար։"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավարկման հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Կարգավորումներ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Եղավ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն օգտագործում է ձեր <xliff:g id="TYPES_LIST">%2$s</xliff:g>:"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Հավելվածներն օգտագործում են ձեր <xliff:g id="TYPES_LIST">%s</xliff:g>:"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" և "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Տվիչներն անջատած են"</string>
<string name="device_services" msgid="1549944177856658705">"Սարքի ծառայություններ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dfed57b..7cc1b89 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Setelan"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Oke"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hapus Heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensor nonaktif"</string>
<string name="device_services" msgid="1549944177856658705">"Layanan Perangkat"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 57cdb27..8b686b8 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Stillingar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ég skil"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Vista SysUI-gögn"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> er að nota <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Forrit eru að nota <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"myndavél"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"staðsetning"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"hljóðnemi"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Slökkt á skynjurum"</string>
<string name="device_services" msgid="1549944177856658705">"Tækjaþjónusta"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 679eb55..35742fd 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Impostazioni"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Esegui dump heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"L\'app <xliff:g id="APP">%1$s</xliff:g> sta usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"Fotocamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"luogo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"un microfono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensori disattivati"</string>
<string name="device_services" msgid="1549944177856658705">"Servizi del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index b6a723f..1029bb2 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"הגדרות"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"הבנתי"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"ערימת Dump SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> משתמשת ב<xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"אפליקציות משתמשות ב<xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" וגם "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"מצלמה"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"מיקום"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"מיקרופון"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"החיישנים כבויים"</string>
<string name="device_services" msgid="1549944177856658705">"שירותים למכשיר"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b70e2e2..fedd9bb7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ヒープのダンプ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>は<xliff:g id="TYPES_LIST">%2$s</xliff:g>を使用しています。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"アプリは<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しています。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 、 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"カメラ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"現在地情報"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"マイク"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"センサー OFF"</string>
<string name="device_services" msgid="1549944177856658705">"デバイス サービス"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 0dda483..5c55112 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"პარამეტრები"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"გასაგებია"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI გროვის გამოტანა"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>-ის მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"აპლიკაციების მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" და "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"კამერა"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"მდებარეობა"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"მიკროფონი"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"სენსორების გამორთვა"</string>
<string name="device_services" msgid="1549944177856658705">"მოწყობილობის სერვისები"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 27bc3ab..94c8ea3 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Параметрлер"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Түсінікті"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> қолданбасында <xliff:g id="TYPES_LIST">%2$s</xliff:g> пайдалануда."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Қолданбаларда <xliff:g id="TYPES_LIST">%s</xliff:g> пайдаланылуда."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" және "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"геодерек"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчиктер өшірулі"</string>
<string name="device_services" msgid="1549944177856658705">"Құрылғы қызметтері"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 36d5aa8..5ba460a 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ការកំណត់"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"យល់ហើយ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"ចម្លង SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> កំពុងប្រើ <xliff:g id="TYPES_LIST">%2$s</xliff:g> របស់អ្នក។"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"កម្មវិធីកំពុងប្រើ <xliff:g id="TYPES_LIST">%s</xliff:g> របស់អ្នក។"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" និង "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"កាមេរ៉ា"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ទីតាំង"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"មីក្រូហ្វូន"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"បិទឧបករណ៍ចាប់សញ្ញា"</string>
<string name="device_services" msgid="1549944177856658705">"សេវាកម្មឧបករណ៍"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មានចំណងជើង"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 2034472..7b8ed88 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ಅರ್ಥವಾಯಿತು"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ಅನ್ನು <xliff:g id="APP">%1$s</xliff:g> ಬಳಸುತ್ತಿದೆ."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%s</xliff:g> ಅನ್ನು ಆ್ಯಪ್ಗಳು ಬಳಸುತ್ತಿವೆ."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ಮತ್ತು "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ಕ್ಯಾಮರಾ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ಸ್ಥಳ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ಮೈಕ್ರೋಫೋನ್"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ಸೆನ್ಸರ್ಗಳು ಆಫ್"</string>
<string name="device_services" msgid="1549944177856658705">"ಸಾಧನ ಸೇವೆಗಳು"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ef4a5f6..8d1177b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"설정"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"확인"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="TYPES_LIST">%2$s</xliff:g>을(를) 사용 중입니다."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"애플리케이션이 <xliff:g id="TYPES_LIST">%s</xliff:g>을(를) 사용 중입니다."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 및 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"카메라"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"위치"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"마이크"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"센서 사용 안함"</string>
<string name="device_services" msgid="1549944177856658705">"기기 서비스"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index cfd91b5..794de98 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Жөндөөлөр"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Түшүндүм"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> төмөнкүлөрдү колдонуп жатат: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Колдонмолор төмөнкүлөрдү пайдаланып жатышат: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" жана "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"жайгашкан жер"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сенсорлорду өчүрүү"</string>
<string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 90b5ad2..2fe3f80 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ການຕັ້ງຄ່າ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ຂອງທ່ານ."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ແອັບພລິເຄຊັນກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%s</xliff:g> ຂອງທ່ານ."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ແລະ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ກ້ອງຖ່າຍຮູບ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ສະຖານທີ່"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ໄມໂຄຣໂຟນ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ປິດການຮັບຮູ້ຢູ່"</string>
<string name="device_services" msgid="1549944177856658705">"ບໍລິການອຸປະກອນ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5c8e8d9..4489b7d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nustatymai"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Supratau"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Pat. „SysUI“ krūvą"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Programa „<xliff:g id="APP">%1$s</xliff:g>“ naudoja: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programos naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ir "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparatą"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vietovę"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoną"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Jutikliai išjungti"</string>
<string name="device_services" msgid="1549944177856658705">"Įrenginio paslaugos"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index cbe0768..d4826e4 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -28,15 +28,15 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g> (ņemot vērā lietojumu)"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
<string name="invalid_charger" msgid="4370074072117767416">"Nevar veikt uzlādi, izmantojot USB. Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nevar veikt uzlādi, izmantojot USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Iestatījumi"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora jaudas taupīšanas režīmu?"</string>
- <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+ <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora enerģijas taupīšanas režīmu"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ieslēgt"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Iestatījumi"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automātiska ekrāna pagriešana"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Līdz <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Tumšais motīvs"</string>
- <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Jaudas taupīšana"</string>
+ <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Enerģijas taupīšana"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Saulrietā"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -502,9 +502,9 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"Vai noņemt lietotāju?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Tiks dzēstas visas šī lietotāja lietotnes un dati."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Noņemt"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"Akumulatora jaudas taupīšanas režīms ir ieslēgts"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Akumulatora enerģijas taupīšanas režīms ir ieslēgts"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Samazina veiktspēju un fona datus"</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izslēgt akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izslēgt akumulatora enerģijas taupīšanas režīmu"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Pakalpojums, kas nodrošina šo funkciju, iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vai vēlaties sākt ierakstīšanu/apraidi?"</string>
@@ -780,8 +780,8 @@
<item quantity="other">%d minūtes</item>
</plurals>
<string name="battery_panel_title" msgid="5931157246673665963">"Akumulatora lietojums"</string>
- <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
- <string name="battery_detail_switch_title" msgid="6940976502957380405">"Akumulatora jaudas taupīšanas režīms"</string>
+ <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Akumulatora enerģijas taupīšanas režīms uzlādes laikā nav pieejams."</string>
+ <string name="battery_detail_switch_title" msgid="6940976502957380405">"Akumulatora enerģijas taupīšanas režīms"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"Samazina veiktspēju un fona datus."</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Sākumvietas taustiņš"</string>
@@ -982,14 +982,21 @@
<string name="slice_permission_checkbox" msgid="4242888137592298523">"Atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> rādīt sadaļas no jebkuras lietotnes"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"Atļaut"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"Neatļaut"</string>
- <string name="auto_saver_title" msgid="6873691178754086596">"Pieskarieties, lai iestatītu akumulatora jaudas taupīšanas režīma grafiku"</string>
+ <string name="auto_saver_title" msgid="6873691178754086596">"Pieskarieties, lai iestatītu akumulatora enerģijas taupīšanas režīma grafiku"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"Ieslēgt, ja akumulators var izlādēties"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nē, paldies"</string>
<string name="auto_saver_enabled_title" msgid="4294726198280286333">"Ieslēgts akumulatora enerģijas taupīšanas režīma grafiks"</string>
- <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Tiklīdz akumulatora uzlādes līmenis būs zemāks nekā <xliff:g id="PERCENTAGE">%d</xliff:g>%%, tiks automātiski ieslēgts akumulatora jaudas taupīšanas režīms."</string>
+ <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Tiklīdz akumulatora uzlādes līmenis būs zemāks nekā <xliff:g id="PERCENTAGE">%d</xliff:g>%%, tiks automātiski ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Iestatījumi"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Labi"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Lietotne <xliff:g id="APP">%1$s</xliff:g> izmanto funkcijas <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Lietojumprogrammas izmanto šādas funkcijas: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" un "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"atrašanās vieta"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofons"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensori izslēgti"</string>
<string name="device_services" msgid="1549944177856658705">"Ierīces pakalpojumi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5a000de..4836ecf 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Поставки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Сфатив"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Извади SysUI-слика"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> користи <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликациите користат <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"локација"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензорите се исклучени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуги за уредот"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2239227..863ce11 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ക്രമീകരണം"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"മനസ്സിലായി"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ഉപയോഗിക്കുന്നു."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ആപ്പുകൾ നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%s</xliff:g> ഉപയോഗിക്കുന്നു."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" കൂടാതെ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ക്യാമറ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ലൊക്കേഷന്"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"മൈക്രോഫോൺ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"സെൻസറുകൾ ഓഫാണ്"</string>
<string name="device_services" msgid="1549944177856658705">"ഉപകരണ സേവനങ്ങള്"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8141ef3..107c310 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Тохиргоо"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ойлголоо"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> таны <xliff:g id="TYPES_LIST">%2$s</xliff:g>-г ашиглаж байна."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" болон "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камер"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"байршил"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Мэдрэгчийг унтраах"</string>
<string name="device_services" msgid="1549944177856658705">"Төхөөрөмжийн үйлчилгээ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 79b7ae8..bd2c3a5 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिंग्ज"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"समजले"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI हीप डंप करा"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> तुमचे <xliff:g id="TYPES_LIST">%2$s</xliff:g> वापरत आहे."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ॲप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" आणि "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"कॅमेरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सर बंद आहेत"</string>
<string name="device_services" msgid="1549944177856658705">"डिव्हाइस सेवा"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 37cbb7e..029571b 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Tetapan"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Longgok Tmbunn SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> sedang menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g> anda."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Penderia dimatikan"</string>
<string name="device_services" msgid="1549944177856658705">"Perkhidmatan Peranti"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 376ed2f..6e632af 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ဆက်တင်များ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ရပါပြီ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> က သင်၏ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"အပလီကေးရှင်းများက သင်၏ <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"၊ "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" နှင့် "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ကင်မရာ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"တည်နေရာ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"မိုက်ခရိုဖုန်း"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
<string name="device_services" msgid="1549944177856658705">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 2626830..5e29ca4 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Innstillinger"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Greit"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> bruker <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apper bruker <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"posisjon"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorer er av"</string>
<string name="device_services" msgid="1549944177856658705">"Enhetstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index d962af7..098e0b1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिङहरू"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"बुझेँ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको <xliff:g id="TYPES_LIST">%2$s</xliff:g> प्रयोग गर्दै छ।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"एपहरूले तपाईंको <xliff:g id="TYPES_LIST">%s</xliff:g> प्रयोग गर्दै छन्।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" र "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"क्यामेरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सरहरू निष्क्रिय छन्"</string>
<string name="device_services" msgid="1549944177856658705">"यन्त्रका सेवाहरू"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7a4de75..e501218 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -433,7 +433,7 @@
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Apparaat"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Veeg omhoog om te schakelen tussen apps"</string>
+ <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe omhoog om te schakelen tussen apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep naar rechts om snel tussen apps te schakelen"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Overzicht in-/uitschakelen"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opgeladen"</string>
@@ -452,12 +452,12 @@
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"Minder urgente meldingen onderaan"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"Tik nog eens om te openen"</string>
- <string name="keyguard_unlock" msgid="8031975796351361601">"Veeg omhoog om te openen"</string>
- <string name="keyguard_retry" msgid="886802522584053523">"Veeg omhoog om het opnieuw te proberen"</string>
+ <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
+ <string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <string name="phone_hint" msgid="6682125338461375925">"Vegen voor telefoon"</string>
- <string name="voice_hint" msgid="7476017460191291417">"Vegen vanaf pictogram voor spraakassistent"</string>
+ <string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
+ <string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Helemaal stil. Hiermee worden schermlezers ook op stil gezet."</string>
<string name="interruption_level_none" msgid="219484038314193379">"Helemaal stil"</string>
@@ -566,7 +566,7 @@
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Vertrouwde gegevens openen"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Je beheerder heeft netwerkregistratie ingeschakeld, waarmee verkeer op je apparaat wordt bijgehouden.\n\nNeem contact op met je beheerder voor meer informatie."</string>
- <string name="monitoring_description_vpn" msgid="1685428000684586870">"Je hebt een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+ <string name="monitoring_description_vpn" msgid="1685428000684586870">"Je hebt een app rechten gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nJe bent ook verbonden met een VPN, waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden."</string>
@@ -644,7 +644,7 @@
<string name="output_service_bt_wifi" msgid="7186882540475524124">"Bluetooth en wifi"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Systeem-UI-tuner"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"Percentage ingebouwde batterij weergeven"</string>
- <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Accupercentage weergeven in het pictogram op de statusbalk wanneer er niet wordt opgeladen"</string>
+ <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Accupercentage weergeven in het icoon op de statusbalk wanneer er niet wordt opgeladen"</string>
<string name="quick_settings" msgid="6211774484997470203">"Snelle instellingen"</string>
<string name="status_bar" msgid="4357390266055077437">"Statusbalk"</string>
<string name="overview" msgid="3522318590458536816">"Overzicht"</string>
@@ -861,8 +861,8 @@
<string name="accessibility_key" msgid="3471162841552818281">"Aangepaste navigatieknop"</string>
<string name="left_keycode" msgid="8211040899126637342">"Toetscode links"</string>
<string name="right_keycode" msgid="2480715509844798438">"Toetscode rechts"</string>
- <string name="left_icon" msgid="5036278531966897006">"Pictogram links"</string>
- <string name="right_icon" msgid="1103955040645237425">"Pictogram rechts"</string>
+ <string name="left_icon" msgid="5036278531966897006">"Icoon links"</string>
+ <string name="right_icon" msgid="1103955040645237425">"Icoon rechts"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Houd vast en sleep om tegels toe te voegen"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Houd vast en sleep om tegels opnieuw in te delen"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Sleep hier naartoe om te verwijderen"</string>
@@ -872,12 +872,12 @@
<string-array name="clock_options">
<item msgid="3986445361435142273">"Uren, minuten en seconden weergeven"</item>
<item msgid="1271006222031257266">"Uren en minuten weergeven (standaard)"</item>
- <item msgid="6135970080453877218">"Dit pictogram niet weergeven"</item>
+ <item msgid="6135970080453877218">"Dit icoon niet weergeven"</item>
</string-array>
<string-array name="battery_options">
<item msgid="7714004721411852551">"Percentage altijd weergeven"</item>
<item msgid="3805744470661798712">"Percentage weergeven tijdens opladen (standaard)"</item>
- <item msgid="8619482474544321778">"Dit pictogram niet weergeven"</item>
+ <item msgid="8619482474544321778">"Dit icoon niet weergeven"</item>
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Pictogrammen voor meldingen met lage prioriteit weergeven"</string>
<string name="other" msgid="429768510980739978">"Overig"</string>
@@ -970,7 +970,7 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobiele data uitzetten?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Je hebt dan geen toegang meer tot data of internet via <xliff:g id="CARRIER">%s</xliff:g>. Internet is alleen nog beschikbaar via wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"je provider"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"Aangezien een app een toestemmingsverzoek afdekt, kan Instellingen je reactie niet verifiëren."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"Aangezien een app een rechtenverzoek afdekt, kan Instellingen je reactie niet verifiëren."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weer te geven?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Instellingen"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> gebruikt je <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps gebruiken je <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"locatie"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfoon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensoren uit"</string>
<string name="device_services" msgid="1549944177856658705">"Apparaatservices"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index e112f44..bfd4bd7 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ସେଟିଂସ୍"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ବୁଝିଗଲି"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ଆପ୍ଲିକେସନ୍ଗୁଡିକ ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ଏବଂ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"କ୍ୟାମେରା"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ଲୋକେସନ୍"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ମାଇକ୍ରୋଫୋନ୍"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ସେନ୍ସର୍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
<string name="device_services" msgid="1549944177856658705">"ଡିଭାଇସ୍ ସେବାଗୁଡିକ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6ac824b..1df9192 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ਸੈਟਿੰਗਾਂ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ਸਮਝ ਲਿਆ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ਹੀਪ ਡੰਪ ਕਰੋ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀਆਂ ਹਨ।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ਅਤੇ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ਕੈਮਰਾ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ਟਿਕਾਣਾ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ਸੈਂਸਰ ਬੰਦ ਕਰੋ"</string>
<string name="device_services" msgid="1549944177856658705">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f5ef1a0..56fcbb2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ustawienia"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Zrzut stosu SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> używa: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacje używają: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"aparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokalizacja"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Wyłącz czujniki"</string>
<string name="device_services" msgid="1549944177856658705">"Usługi urządzenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c8eaa0d..88f6032 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configurações"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"O app <xliff:g id="APP">%1$s</xliff:g> está usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 341efff..5fdb285 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Definições"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar pilha SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"A app <xliff:g id="APP">%1$s</xliff:g> está a utilizar o(a) <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"As aplicações estão a utilizar o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
@@ -1015,7 +1022,7 @@
<string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas prioritárias irão:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecer na parte superior da secção de conversas."</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrar a imagem do perfil no ecrã de bloqueio."</string>
- <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecem como balões flutuantes por cima de apps."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecer como balões flutuantes por cima de apps."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompem o modo Não incomodar."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Definições"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c8eaa0d..88f6032 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configurações"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"O app <xliff:g id="APP">%1$s</xliff:g> está usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 08542c0..d5eecc7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Setări"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Extrageți memoria SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> folosește <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicațiile folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" și "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cameră foto"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"locație"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori dezactivați"</string>
<string name="device_services" msgid="1549944177856658705">"Servicii pentru dispozitiv"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 12c489e..5085022 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Открыть настройки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ОК"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Передача SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"В приложении \"<xliff:g id="APP">%1$s</xliff:g>\" используется <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"В приложениях используется <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"местоположение"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчики отключены"</string>
<string name="device_services" msgid="1549944177856658705">"Сервисы устройства"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 412050f..ff7e816 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"සැකසීම්"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"තේරුණා"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ඔබේ <xliff:g id="TYPES_LIST">%2$s</xliff:g> භාවිත කරමින් සිටී."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"යෙදුම් ඔබේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරමින් සිටී."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" සහ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"කැමරාව"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ස්ථානය"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"මයික්රෝෆෝනය"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"සංවේදක ක්රියාවිරහිතයි"</string>
<string name="device_services" msgid="1549944177856658705">"උපාංග සේවා"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f657d4f..a86da96 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavenia"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Dobre"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> používa zoznam <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikácie používajú zoznam <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofón"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzory sú vypnuté"</string>
<string name="device_services" msgid="1549944177856658705">"Služby zariadenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e1e5852..b9039d8 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavitve"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"V redu"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izvoz kopice SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> uporablja <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije uporabljajo <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" in "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokacijo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Izklop za tipala"</string>
<string name="device_services" msgid="1549944177856658705">"Storitve naprave"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 64d7a2e..2972c53 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Cilësimet"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"E kuptova"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hidh grumbullin SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> po përdor <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacionet po përdorin <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dhe "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamerën"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vendndodhjen"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonin"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorët joaktivë"</string>
<string name="device_services" msgid="1549944177856658705">"Shërbimet e pajisjes"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index fd6f57e..77cbb96b 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Подешавања"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Важи"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Издвоји SysUI мем."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> користи <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"локацију"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензори су искључени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуге за уређаје"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f96dd27..c7eda45 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Inställningar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="TYPES_LIST">%2$s</xliff:g> används av <xliff:g id="APP">%1$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> används av appar."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" och "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"plats"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorer har inaktiverats"</string>
<string name="device_services" msgid="1549944177856658705">"Enhetstjänster"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8b8c249..2804f2f 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Mipangilio"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Nimeelewa"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> inatumia <xliff:g id="TYPES_LIST">%2$s</xliff:g> yako."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programu zinatumia <xliff:g id="TYPES_LIST">%s</xliff:g> yako."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" na "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"mahali"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"maikrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Umezima vitambuzi"</string>
<string name="device_services" msgid="1549944177856658705">"Huduma za Kifaa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index b97e266..ee176fa 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"அமைப்புகள்"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"சரி"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"உங்கள் <xliff:g id="TYPES_LIST">%2$s</xliff:g>ஐ <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் பயன்படுத்துகிறது."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"உங்கள் <xliff:g id="TYPES_LIST">%s</xliff:g> ஆகியவற்றை ஆப்ஸ் பயன்படுத்துகின்றன."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" மற்றும் "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"கேமரா"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"இருப்பிடம்"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"மைக்ரோஃபோன்"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"சென்சார்களை ஆஃப் செய்தல்"</string>
<string name="device_services" msgid="1549944177856658705">"சாதன சேவைகள்"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 13319d9..dc5ea1f 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"సెట్టింగ్లు"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"అర్థమైంది"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"డంప్ SysUI హీప్"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> మీ <xliff:g id="TYPES_LIST">%2$s</xliff:g>ని ఉపయోగిస్తోంది."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"అప్లికేషన్లు మీ <xliff:g id="TYPES_LIST">%s</xliff:g>ని ఉపయోగిస్తున్నాయి."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" మరియు "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"కెమెరా"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"లొకేషన్"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"మైక్రోఫోన్"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"సెన్సార్లు ఆఫ్"</string>
<string name="device_services" msgid="1549944177856658705">"పరికర సేవలు"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e1c0e7e..ba9fd29 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"การตั้งค่า"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"รับทราบ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ใช้<xliff:g id="TYPES_LIST">%2$s</xliff:g>ของคุณอยู่"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"หลายแอปพลิเคชันใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณอยู่"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" และ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"กล้องถ่ายรูป"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ตำแหน่ง"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ไมโครโฟน"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ปิดเซ็นเซอร์"</string>
<string name="device_services" msgid="1549944177856658705">"บริการของอุปกรณ์"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 20a34e1..069438f 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Mga Setting"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Ginagamit ng <xliff:g id="APP">%1$s</xliff:g> ang iyong <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ginagamit ng mga application ang iyong <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" at "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasyon"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikropono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Naka-off ang mga sensor"</string>
<string name="device_services" msgid="1549944177856658705">"Mga Serbisyo ng Device"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4146f30..649b9af 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ayarlar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Anladım"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Yığın Dökümü"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> şunları kullanıyor: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Uygulamalar şunları kullanıyor: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ve "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"konum"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensörler kapalı"</string>
<string name="device_services" msgid="1549944177856658705">"Cihaz Hizmetleri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 11eb18c..6cb3ac8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Налаштування"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Додаток <xliff:g id="APP">%1$s</xliff:g> використовує <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Додатки використовують <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"місце"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"мікрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчики вимкнено"</string>
<string name="device_services" msgid="1549944177856658705">"Сервіси на пристрої"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index d7645e9..804c334 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ترتیبات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"سمجھ آ گئی"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> آپ کی <xliff:g id="TYPES_LIST">%2$s</xliff:g> کا استعمال کر رہی ہے۔"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ایپلیکیشنز آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں۔"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" اور "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"کیمرا"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"مقام"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"مائیکروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"سینسرز آف ہیں"</string>
<string name="device_services" msgid="1549944177856658705">"آلہ کی سروس"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 1fc4f9b..6193d33 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Sozlamalar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ishlatmoqda: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ilovalarda ishlatilmoqda: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" va "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"joylashuv"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorlar nofaol"</string>
<string name="device_services" msgid="1549944177856658705">"Qurilma xizmatlari"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8df5ee5..97ffbc6 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Cài đặt"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Trích xuất bộ nhớ SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> đang dùng <xliff:g id="TYPES_LIST">%2$s</xliff:g> của bạn."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Các ứng dụng đang dùng <xliff:g id="TYPES_LIST">%s</xliff:g> của bạn."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" và "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"máy ảnh"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vị trí"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrô"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Tắt cảm biến"</string>
<string name="device_services" msgid="1549944177856658705">"Dịch vụ cho thiết bị"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c51982c..b9b146c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"设置"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"转储 SysUI 堆"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>正在使用您的<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多个应用正在使用您的<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相机"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置信息"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麦克风"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"已关闭传感器"</string>
<string name="device_services" msgid="1549944177856658705">"设备服务"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa9945f..f2cb185 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"轉儲 SysUI 堆"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"感應器已關閉"</string>
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 92bdfc3..69b5294 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"我知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"傾印 SysUI 記憶體快照"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"已關閉感應器"</string>
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4ae1267..5b899f9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Izilungiselelo"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ngiyezwa"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"I-Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"I-<xliff:g id="APP">%1$s</xliff:g> isebenzisa i-<xliff:g id="TYPES_LIST">%2$s</xliff:g> yakho."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" kanye "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ikhamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"indawo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"imakrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Izinzwa zivaliwe"</string>
<string name="device_services" msgid="1549944177856658705">"Amasevisi edivayisi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f407a8d..fa620df 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -161,10 +161,6 @@
<!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
<integer name="ambient_notification_extension_time">10000</integer>
- <!-- In multi-window, determines whether the stack where recents lives should grow from
- the smallest position when being launched. -->
- <bool name="recents_grow_in_multiwindow">true</bool>
-
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">250</integer>
@@ -522,6 +518,8 @@
<!-- Defines the blacklist for system icons. That is to say, the icons in the status bar that
are part of the blacklist are never displayed. Each item in the blacklist must be a string
defined in core/res/res/config.xml to properly blacklist the icon.
+
+ TODO: See if we can rename this config variable.
-->
<string-array name="config_statusBarIconBlackList" translatable="false">
<item>@*android:string/status_bar_rotate</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8b6543a..77d3f45 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2838,4 +2838,9 @@
<string name="udfps_hbm_enable_command" translatable="false"></string>
<!-- Device-specific payload for disabling the high-brightness mode -->
<string name="udfps_hbm_disable_command" translatable="false"></string>
+
+ <!-- One-Handed Tutorial title [CHAR LIMIT=60] -->
+ <string name="one_handed_tutorial_title">Using one-handed mode</string>
+ <!-- One-Handed Tutorial description [CHAR LIMIT=NONE] -->
+ <string name="one_handed_tutorial_description">To exit, swipe up from the bottom of the screen or tap anywhere above the app</string>
</resources>
diff --git a/packages/SystemUI/res/xml/one_handed_tutorial.xml b/packages/SystemUI/res/xml/one_handed_tutorial.xml
new file mode 100644
index 0000000..dc54caf
--- /dev/null
+++ b/packages/SystemUI/res/xml/one_handed_tutorial.xml
@@ -0,0 +1,67 @@
+<?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/one_handed_tutorial_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal | center_vertical"
+ android:background="@android:color/transparent">
+
+ <ImageView
+ android:id="@+id/one_handed_tutorial_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:gravity="center_horizontal"
+ android:src="@drawable/one_handed_tutorial"
+ android:scaleType="centerInside" />
+
+ <TextView
+ android:id="@+id/one_handed_tutorial_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:gravity="center_horizontal"
+ android:textAlignment="center"
+ android:fontFamily="google-sans-medium"
+ android:text="@string/one_handed_tutorial_title"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:textColor="@android:color/white"/>
+
+ <TextView
+ android:id="@+id/one_handed_tutorial_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:layout_marginStart="86dp"
+ android:layout_marginEnd="86dp"
+ android:gravity="center_horizontal"
+ android:fontFamily="roboto-regular"
+ android:text="@string/one_handed_tutorial_description"
+ android:textAlignment="center"
+ android:textSize="14sp"
+ android:textStyle="normal"
+ android:alpha="0.7"
+ android:textColor="@android:color/white"/>
+</LinearLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 158763a..ecf1c2c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,10 +1,7 @@
package com.android.keyguard;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
@@ -24,16 +21,10 @@
import android.widget.RelativeLayout;
import android.widget.TextClock;
-import androidx.annotation.VisibleForTesting;
-
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
-import com.android.keyguard.clock.ClockManager;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
@@ -42,16 +33,12 @@
import java.util.Arrays;
import java.util.TimeZone;
-import javax.inject.Inject;
-import javax.inject.Named;
-
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
- private static final boolean CUSTOM_CLOCKS_ENABLED = true;
/**
* Animation fraction when text is transitioned to/from bold.
@@ -59,21 +46,6 @@
private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
/**
- * Controller used to track StatusBar state to know when to show the big_clock_container.
- */
- private final StatusBarStateController mStatusBarStateController;
-
- /**
- * Color extractor used to apply colors from wallpaper to custom clock faces.
- */
- private final SysuiColorExtractor mSysuiColorExtractor;
-
- /**
- * Manager used to know when to show a custom clock face.
- */
- private final ClockManager mClockManager;
-
- /**
* Layout transition that scales the default clock face.
*/
private final Transition mTransition;
@@ -130,42 +102,8 @@
private boolean mSupportsDarkText;
private int[] mColorPalette;
- /**
- * Track the state of the status bar to know when to hide the big_clock_container.
- */
- private int mStatusBarState;
-
- private final StatusBarStateController.StateListener mStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- mStatusBarState = newState;
- updateBigClockVisibility();
- }
- };
-
- private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
-
- /**
- * Listener for changes to the color palette.
- *
- * The color palette changes when the wallpaper is changed.
- */
- private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
- if ((which & WallpaperManager.FLAG_LOCK) != 0) {
- updateColors();
- }
- };
-
- @Inject
- public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
- ClockManager clockManager) {
+ public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
- mStatusBarStateController = statusBarStateController;
- mStatusBarState = mStatusBarStateController.getState();
- mSysuiColorExtractor = colorExtractor;
- mClockManager = clockManager;
mClockTransition = new ClockVisibilityTransition().setCutoff(
1 - TO_BOLD_TRANSITION_FRACTION);
@@ -197,29 +135,7 @@
mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (CUSTOM_CLOCKS_ENABLED) {
- mClockManager.addOnClockChangedListener(mClockChangedListener);
- }
- mStatusBarStateController.addCallback(mStateListener);
- mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
- updateColors();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (CUSTOM_CLOCKS_ENABLED) {
- mClockManager.removeOnClockChangedListener(mClockChangedListener);
- }
- mStatusBarStateController.removeCallback(mStateListener);
- mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
- setClockPlugin(null);
- }
-
- private void setClockPlugin(ClockPlugin plugin) {
+ void setClockPlugin(ClockPlugin plugin, int statusBarState) {
// Disconnect from existing plugin.
if (mClockPlugin != null) {
View smallClockView = mClockPlugin.getView();
@@ -228,7 +144,7 @@
}
if (mBigClockContainer != null) {
mBigClockContainer.removeAllViews();
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
mClockPlugin.onDestroyView();
mClockPlugin = null;
@@ -256,7 +172,7 @@
View bigClockView = plugin.getBigClockView();
if (bigClockView != null && mBigClockContainer != null) {
mBigClockContainer.addView(bigClockView);
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
// Hide default clock.
if (!plugin.shouldShowStatusArea()) {
@@ -275,7 +191,7 @@
/**
* Set container for big clock face appearing behind NSSL and KeyguardStatusView.
*/
- public void setBigClockContainer(ViewGroup container) {
+ public void setBigClockContainer(ViewGroup container, int statusBarState) {
if (mClockPlugin != null && container != null) {
View bigClockView = mClockPlugin.getBigClockView();
if (bigClockView != null) {
@@ -283,7 +199,7 @@
}
}
mBigClockContainer = container;
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
/**
@@ -407,9 +323,7 @@
}
}
- private void updateColors() {
- ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK);
+ void updateColors(ColorExtractor.GradientColors colors) {
mSupportsDarkText = colors.supportsDarkText();
mColorPalette = colors.getColorPalette();
if (mClockPlugin != null) {
@@ -417,12 +331,12 @@
}
}
- private void updateBigClockVisibility() {
+ void updateBigClockVisibility(int statusBarState) {
if (mBigClockContainer == null) {
return;
}
- final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
- || mStatusBarState == StatusBarState.SHADE_LOCKED;
+ final boolean inDisplayState = statusBarState == StatusBarState.KEYGUARD
+ || statusBarState == StatusBarState.SHADE_LOCKED;
final int visibility = !mShowingHeader && inDisplayState
&& mBigClockContainer.getChildCount() != 0 ? View.VISIBLE : View.GONE;
if (mBigClockContainer.getVisibility() != visibility) {
@@ -506,16 +420,6 @@
}
}
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- ClockManager.ClockChangedListener getClockChangedListener() {
- return mClockChangedListener;
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- StatusBarStateController.StateListener getStateListener() {
- return mStateListener;
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardClockSwitch:");
pw.println(" mClockPlugin: " + mClockPlugin);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
new file mode 100644
index 0000000..f17f1ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -0,0 +1,119 @@
+/*
+ * 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.keyguard;
+
+import android.app.WallpaperManager;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+
+import javax.inject.Inject;
+
+/**
+ * Injectable controller for {@link KeyguardClockSwitch}.
+ */
+public class KeyguardClockSwitchController {
+ private static final boolean CUSTOM_CLOCKS_ENABLED = true;
+
+ private final StatusBarStateController mStatusBarStateController;
+ private final SysuiColorExtractor mColorExtractor;
+ private final ClockManager mClockManager;
+ private KeyguardClockSwitch mView;
+
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mView.updateBigClockVisibility(newState);
+ }
+ };
+
+ /**
+ * Listener for changes to the color palette.
+ *
+ * The color palette changes when the wallpaper is changed.
+ */
+ private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
+ if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ mView.updateColors(getGradientColors());
+ }
+ };
+
+ private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+
+ private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ if (CUSTOM_CLOCKS_ENABLED) {
+ mClockManager.addOnClockChangedListener(mClockChangedListener);
+ }
+ mStatusBarStateController.addCallback(mStateListener);
+ mColorExtractor.addOnColorsChangedListener(mColorsListener);
+ mView.updateColors(getGradientColors());
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (CUSTOM_CLOCKS_ENABLED) {
+ mClockManager.removeOnClockChangedListener(mClockChangedListener);
+ }
+ mStatusBarStateController.removeCallback(mStateListener);
+ mColorExtractor.removeOnColorsChangedListener(mColorsListener);
+ mView.setClockPlugin(null, mStatusBarStateController.getState());
+ }
+ };
+
+ @Inject
+ public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
+ SysuiColorExtractor colorExtractor, ClockManager clockManager) {
+ mStatusBarStateController = statusBarStateController;
+ mColorExtractor = colorExtractor;
+ mClockManager = clockManager;
+ }
+
+ /**
+ * Attach the controller to the view it relates to.
+ */
+ public void attach(KeyguardClockSwitch view) {
+ mView = view;
+ if (mView.isAttachedToWindow()) {
+ mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
+ }
+ mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+
+ /**
+ * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
+ */
+ public void setBigClockContainer(ViewGroup bigClockContainer) {
+ mView.setBigClockContainer(bigClockContainer, mStatusBarStateController.getState());
+ }
+
+ private void setClockPlugin(ClockPlugin plugin) {
+ mView.setClockPlugin(plugin, mStatusBarStateController.getState());
+ }
+
+ private ColorExtractor.GradientColors getGradientColors() {
+ return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 76adf04..1c47aa0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -141,7 +141,7 @@
// Sending empty PIN here to query the number of remaining PIN attempts
new CheckSimPin("", mSubId) {
void onSimCheckResponse(final PinResult result) {
- Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result "
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ result.toString());
if (result.getAttemptsRemaining() >= 0) {
mRemainingAttempts = result.getAttemptsRemaining();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index a84664c..5148dd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -195,7 +195,7 @@
void onSimLockChangedResponse(final PinResult result) {
if (result == null) Log.e(LOG_TAG, "onSimCheckResponse, pin result is NULL");
else {
- Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result "
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ result.toString());
if (result.getAttemptsRemaining() >= 0) {
mRemainingAttempts = result.getAttemptsRemaining();
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 5869815..521bb8d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -225,7 +225,7 @@
}
Dependency.get(TunerService.class)
- .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ .addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mIsSubscribedForTunerUpdates = true;
}
@@ -278,8 +278,8 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
- ArraySet<String> icons = StatusBarIconController.getIconBlacklist(
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ ArraySet<String> icons = StatusBarIconController.getIconHideList(
getContext(), newValue);
setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
index 769a344..d5aac1a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
@@ -60,6 +60,20 @@
return instance;
}
+ /**
+ * Gets the object by the element index.
+ *
+ * <p> If the index is bigger than the array size, an {@link ArrayIndexOutOfBoundsException} is
+ * thrown for apps targeting {@link android.os.Build.VERSION_CODES#Q} and later </p>
+ *
+ * @param index the element index
+ * @return T
+ * @see SparseArray#valueAt(int)
+ */
+ public T valueAt(int index) {
+ return mSparseArray.valueAt(index);
+ }
+
@NonNull
protected abstract T createInstance(Display display);
@@ -78,4 +92,13 @@
public void clear() {
mSparseArray.clear();
}
+
+ /**
+ * Gets the element size.
+ *
+ * @return size of all elements
+ */
+ public int getSize() {
+ return mSparseArray.size();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 68a0a65..34f721c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.provider.Settings;
import android.view.Gravity;
@@ -102,6 +103,14 @@
.start();
}
+ void onConfigurationChanged(int configDiff) {
+ if ((configDiff & ActivityInfo.CONFIG_DENSITY) == 0) {
+ return;
+ }
+ applyResourcesValues();
+ mImageView.setImageResource(getIconResId(mMagnificationMode));
+ }
+
private void toggleMagnificationMode() {
final int newMode =
mMagnificationMode ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
@@ -112,7 +121,7 @@
}
private static ImageView createView(Context context) {
- ImageView imageView = new ImageView(context);
+ ImageView imageView = new ImageView(context);
imageView.setClickable(true);
imageView.setFocusable(true);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
index ffc70bc..fe07ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
@@ -36,7 +36,7 @@
@Singleton
public class ModeSwitchesController {
- private final SwitchSupplier mSwitchSupplier;
+ private final DisplayIdIndexSupplier<MagnificationModeSwitch> mSwitchSupplier;
public ModeSwitchesController(Context context) {
mSwitchSupplier = new SwitchSupplier(context,
@@ -44,7 +44,7 @@
}
@VisibleForTesting
- ModeSwitchesController(SwitchSupplier switchSupplier) {
+ ModeSwitchesController(DisplayIdIndexSupplier<MagnificationModeSwitch> switchSupplier) {
mSwitchSupplier = switchSupplier;
}
@@ -81,8 +81,22 @@
magnificationModeSwitch.removeButton();
}
- @VisibleForTesting
- static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
+ /**
+ * Called when the configuration has changed, and it updates magnification button UI.
+ *
+ * @param configDiff a bit mask of the differences between the configurations
+ */
+ @MainThread
+ void onConfigurationChanged(int configDiff) {
+ for (int i = 0; i < mSwitchSupplier.getSize(); i++) {
+ final MagnificationModeSwitch magnificationModeSwitch = mSwitchSupplier.valueAt(i);
+ if (magnificationModeSwitch != null) {
+ magnificationModeSwitch.onConfigurationChanged(configDiff);
+ }
+ }
+ }
+
+ private static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 426e400..816bcf8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -25,6 +25,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
@@ -83,6 +84,9 @@
if (mWindowMagnificationController != null) {
mWindowMagnificationController.onConfigurationChanged(configDiff);
}
+ if (mModeSwitchesController != null) {
+ mModeSwitchesController.onConfigurationChanged(configDiff);
+ }
}
@Override
@@ -97,7 +101,7 @@
mWindowMagnificationController = new WindowMagnificationController(mContext,
mHandler,
new SfVsyncFrameCallbackProvider(),
- null,
+ null, new SurfaceControl.Transaction(),
this);
}
mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
@@ -136,6 +140,13 @@
}
@Override
+ public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ if (mWindowMagnificationConnectionImpl != null) {
+ mWindowMagnificationConnectionImpl.onSourceBoundsChanged(displayId, sourceBounds);
+ }
+ }
+
+ @Override
public void requestWindowMagnificationConnection(boolean connect) {
if (connect) {
setWindowMagnificationConnection();
@@ -225,5 +236,15 @@
}
}
}
+
+ void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onSourceBoundsChanged(displayId, sourceBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform source bounds changed", e);
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 8b6581f..798b751 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -67,7 +67,7 @@
@Surface.Rotation
private int mRotation;
private final Rect mMagnificationFrame = new Rect();
- private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final SurfaceControl.Transaction mTransaction;
private final WindowManager mWm;
@@ -75,6 +75,7 @@
private final Rect mTmpRect = new Rect();
private final Rect mMirrorViewBounds = new Rect();
+ private final Rect mSourceBounds = new Rect();
// The root of the mirrored content
private SurfaceControl mMirrorSurface;
@@ -101,22 +102,14 @@
private final Rect mMagnificationFrameBoundary = new Rect();
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- private final Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback =
- l -> {
- if (mMirrorView != null) {
- final Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale);
- mTransaction.setGeometry(mMirrorSurface, sourceBounds, mTmpRect,
- Surface.ROTATION_0).apply();
- }
- };
+ private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
@Nullable
private MirrorWindowControl mMirrorWindowControl;
- WindowMagnificationController(Context context,
- @NonNull Handler handler,
+ WindowMagnificationController(Context context, @NonNull Handler handler,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
- MirrorWindowControl mirrorWindowControl,
+ MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
@NonNull WindowMagnifierCallback callback) {
mContext = context;
mHandler = handler;
@@ -137,6 +130,7 @@
if (mMirrorWindowControl != null) {
mMirrorWindowControl.setWindowDelegate(this);
}
+ mTransaction = transaction;
setInitialStartBounds();
// Initialize listeners.
@@ -153,6 +147,20 @@
mMirrorSurfaceViewLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> applyTapExcludeRegion();
+
+ mMirrorViewGeometryVsyncCallback =
+ l -> {
+ if (mMirrorView != null && mMirrorSurface != null) {
+ calculateSourceBounds(mMagnificationFrame, mScale);
+ // The final destination for the magnification surface should be at 0,0
+ // since the ViewRootImpl's position will change
+ mTmpRect.set(0, 0, mMagnificationFrame.width(),
+ mMagnificationFrame.height());
+ mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect,
+ Surface.ROTATION_0).apply();
+ mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds);
+ }
+ };
}
private void updateDimensions() {
@@ -350,13 +358,9 @@
* Modifies the placement of the mirrored content when the position of mMirrorView is updated.
*/
private void modifyWindowMagnification(SurfaceControl.Transaction t) {
- // The final destination for the magnification surface should be at 0,0 since the
- // ViewRootImpl's position will change
- mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height());
-
+ mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
updateMirrorViewLayout();
- mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
}
/**
@@ -420,14 +424,14 @@
* Calculates the desired source bounds. This will be the area under from the center of the
* displayFrame, factoring in scale.
*/
- private Rect getSourceBounds(Rect displayFrame, float scale) {
+ private void calculateSourceBounds(Rect displayFrame, float scale) {
int halfWidth = displayFrame.width() / 2;
int halfHeight = displayFrame.height() / 2;
int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale));
int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
- return new Rect(left, top, right, bottom);
+ mSourceBounds.set(left, top, right, bottom);
}
private void setMagnificationFrameBoundary() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index 2adb3eb..e405a89 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -29,4 +29,12 @@
* @param bounds The bounds of window magnifier on the screen.
*/
void onWindowMagnifierBoundsChanged(int displayId, Rect bounds);
+
+ /**
+ * Called when the magnified bounds is changed.
+ *
+ * @param displayId The logical display id.
+ * @param sourceBounds The magnified bounds in screen coordinates.
+ */
+ void onSourceBoundsChanged(int displayId, Rect sourceBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 434bf49..bb57219 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -25,6 +25,8 @@
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
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;
@@ -100,8 +102,11 @@
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -277,7 +282,10 @@
* This can happen when an app cancels a bubbled notification or when the user dismisses a
* bubble.
*/
- void removeNotification(@NonNull NotificationEntry entry, int reason);
+ void removeNotification(
+ @NonNull NotificationEntry entry,
+ @NonNull DismissedByUserStats stats,
+ int reason);
/**
* Called when a bubbled notification has changed whether it should be
@@ -543,6 +551,7 @@
}
});
+ // The new pipeline takes care of this as a NotifDismissInterceptor BubbleCoordinator
mNotificationEntryManager.addNotificationRemoveInterceptor(
new NotificationRemoveInterceptor() {
@Override
@@ -551,7 +560,7 @@
NotificationEntry entry,
int dismissReason) {
final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
- final boolean isUserDimiss = dismissReason == REASON_CANCEL
+ final boolean isUserDismiss = dismissReason == REASON_CANCEL
|| dismissReason == REASON_CLICK;
final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
|| dismissReason == REASON_APP_CANCEL_ALL;
@@ -562,7 +571,7 @@
// previously been dismissed & entry.isRowDismissed would still be true
boolean userRemovedNotif =
(entry != null && entry.isRowDismissed() && !isAppCancel)
- || isClearAll || isUserDimiss || isSummaryCancel;
+ || isClearAll || isUserDismiss || isSummaryCancel;
if (userRemovedNotif) {
return handleDismissalInterception(entry);
@@ -591,8 +600,13 @@
addNotifCallback(new NotifCallback() {
@Override
- public void removeNotification(NotificationEntry entry, int reason) {
- mNotificationEntryManager.performRemoveNotification(entry.getSbn(), reason);
+ public void removeNotification(
+ NotificationEntry entry,
+ DismissedByUserStats dismissedByUserStats,
+ int reason
+ ) {
+ mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
+ dismissedByUserStats, reason);
}
@Override
@@ -612,7 +626,9 @@
mNotificationEntryManager.getActiveNotificationUnfiltered(
mBubbleData.getSummaryKey(groupKey));
if (summary != null) {
- mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
UNDEFINED_DISMISS_REASON);
}
}
@@ -634,7 +650,9 @@
boolean isSummaryThisNotif = summary.getKey().equals(entry.getKey());
if (!isSummaryThisNotif && (summaryChildren == null
|| summaryChildren.isEmpty())) {
- mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
UNDEFINED_DISMISS_REASON);
}
}
@@ -1331,7 +1349,10 @@
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
if (entry != null) {
- cb.removeNotification(entry, REASON_CANCEL);
+ cb.removeNotification(
+ entry,
+ getDismissedByUserStats(entry, true),
+ REASON_CANCEL);
}
}
} else {
@@ -1487,7 +1508,10 @@
} else {
// non-bubbled children can be removed
for (NotifCallback cb : mCallbacks) {
- cb.removeNotification(child, REASON_GROUP_SUMMARY_CANCELED);
+ cb.removeNotification(
+ child,
+ getDismissedByUserStats(child, true),
+ REASON_GROUP_SUMMARY_CANCELED);
}
}
}
@@ -1502,6 +1526,25 @@
}
/**
+ * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
+ * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
+ * Instead, this is taken care of by {@link BubbleCoordinator}.
+ */
+ private DismissedByUserStats getDismissedByUserStats(
+ NotificationEntry entry,
+ boolean isVisible) {
+ return new DismissedByUserStats(
+ DISMISSAL_BUBBLE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotificationEntryManager.getActiveNotificationsCount(),
+ isVisible,
+ NotificationLogger.getNotificationLocation(entry)));
+ }
+
+ /**
* Updates the visibility of the bubbles based on current state.
* Does not un-bubble, just hides or un-hides.
* Updates stack description for TalkBack focus.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e26aa55..318a987 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -458,15 +458,6 @@
mPointerView.setBackground(mPointerDrawable);
}
- /**
- * Hides the IME if it's showing. This is currently done by dispatching a back press to the AV.
- */
- void hideImeIfVisible() {
- if (mKeyboardVisible) {
- performBackPressIfNeeded();
- }
- }
-
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index ea12c95..b3fbfd6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1081,11 +1081,10 @@
final Bubble bubble = mBubbleData.getSelectedBubble();
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
final Intent intent = bubble.getSettingsIntent(mContext);
- collapseStack(() -> {
- mContext.startActivityAsUser(intent, bubble.getUser());
- logBubbleEvent(bubble,
- SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
- });
+ mBubbleData.setExpanded(false);
+ mContext.startActivityAsUser(intent, bubble.getUser());
+ logBubbleEvent(bubble,
+ SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
}
});
@@ -1769,36 +1768,6 @@
}
}
- /**
- * Dismiss the stack of bubbles.
- *
- * @deprecated
- */
- @Deprecated
- void stackDismissed(int reason) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "stackDismissed: reason=" + reason);
- }
- mBubbleData.dismissAll(reason);
- logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
- SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
- }
-
- /**
- * @deprecated use {@link #setExpanded(boolean)} and
- * {@link BubbleData#setSelectedBubble(Bubble)}
- */
- @Deprecated
- @MainThread
- void collapseStack(Runnable endRunnable) {
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "collapseStack(endRunnable)");
- }
- mBubbleData.setExpanded(false);
- // TODO - use the runnable at end of animation
- endRunnable.run();
- }
-
void showExpandedViewContents(int displayId) {
if (mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 075318b..de53168 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -135,6 +135,7 @@
}
override fun onOverlayChanged() {
+ recreatePlayers()
inflateSettingsButton()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index c2631c9..1ae54d6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -55,16 +55,16 @@
holder.seekBar.maxHeight = seekBarDefaultMaxHeight
}
- data.elapsedTime?.let {
- holder.seekBar.setProgress(it)
- holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
- }
-
data.duration?.let {
holder.seekBar.setMax(it)
holder.totalTimeView.setText(DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS))
}
+
+ data.elapsedTime?.let {
+ holder.seekBar.setProgress(it)
+ holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS))
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
index c581ac6..264ace7 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
@@ -42,4 +42,10 @@
default void onOneHandedAnimationCancel(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
}
+
+ /**
+ * Called when OneHanded animator is updating offset
+ */
+ default void onTutorialAnimationUpdate(int offset) {}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
index 1926c44..2b07ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
@@ -28,7 +28,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import javax.inject.Inject;
@@ -121,7 +123,8 @@
private T mEndValue;
private T mCurrentValue;
- private OneHandedAnimationCallback mOneHandedAnimationCallback;
+ private final List<OneHandedAnimationCallback> mOneHandedAnimationCallbacks =
+ new ArrayList<>();
private OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -142,9 +145,11 @@
@Override
public void onAnimationStart(Animator animation) {
mCurrentValue = mStartValue;
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationStart(this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationStart(this);
+ }
+ );
}
@Override
@@ -152,17 +157,21 @@
mCurrentValue = mEndValue;
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
onEndTransaction(mLeash, tx);
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationEnd(tx, this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationEnd(tx, this);
+ }
+ );
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentValue = mEndValue;
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationCancel(this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationCancel(this);
+ }
+ );
}
@Override
@@ -173,6 +182,11 @@
public void onAnimationUpdate(ValueAnimator animation) {
applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(),
animation.getAnimatedFraction());
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onTutorialAnimationUpdate(((Rect) mCurrentValue).top);
+ }
+ );
}
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
@@ -192,9 +206,9 @@
mSurfaceTransactionHelper = helper;
}
- OneHandedTransitionAnimator<T> setOneHandedAnimationCallback(
+ OneHandedTransitionAnimator<T> setOneHandedAnimationCallbacks(
OneHandedAnimationCallback callback) {
- mOneHandedAnimationCallback = callback;
+ mOneHandedAnimationCallbacks.add(callback);
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
index c0b9258..8550959 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -82,6 +82,7 @@
private OneHandedAnimationController mAnimationController;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private OneHandedTutorialHandler mTutorialHandler;
private List<OneHandedTransitionCallback> mTransitionCallbacks = new ArrayList<>();
@VisibleForTesting
@@ -148,7 +149,8 @@
@Inject
public OneHandedDisplayAreaOrganizer(Context context,
DisplayController displayController,
- OneHandedAnimationController animationController) {
+ OneHandedAnimationController animationController,
+ OneHandedTutorialHandler tutorialHandler) {
mUpdateHandler = new Handler(OneHandedThread.get().getLooper(), mUpdateCallback);
mAnimationController = animationController;
mDisplayController = displayController;
@@ -157,6 +159,7 @@
mEnterExitAnimationDurationMs = context.getResources().getInteger(
com.android.systemui.R.integer.config_one_handed_translate_animation_duration);
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mTutorialHandler = tutorialHandler;
}
@Override
@@ -272,7 +275,8 @@
mAnimationController.getAnimator(leash, fromBounds, toBounds);
if (animator != null) {
animator.setTransitionDirection(direction)
- .setOneHandedAnimationCallback(mOneHandedAnimationCallback)
+ .setOneHandedAnimationCallbacks(mOneHandedAnimationCallback)
+ .setOneHandedAnimationCallbacks(mTutorialHandler.getAnimationCallback())
.setDuration(durationMs)
.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
index 71c5f80..ded3861 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
@@ -53,8 +53,8 @@
*/
@Singleton
public class OneHandedGestureHandler implements OneHandedTransitionCallback,
- NavigationModeController.ModeChangedListener,
- DisplayChangeController.OnDisplayChangingListener {
+ NavigationModeController.ModeChangedListener,
+ DisplayChangeController.OnDisplayChangingListener {
private static final String TAG = "OneHandedGestureHandler";
private static final boolean DEBUG_GESTURE = false;
@@ -87,8 +87,8 @@
* Constructor of OneHandedGestureHandler, we only handle the gesture of
* {@link Display#DEFAULT_DISPLAY}
*
- * @param context {@link Context}
- * @param displayController {@link DisplayController}
+ * @param context {@link Context}
+ * @param displayController {@link DisplayController}
* @param navigationModeController {@link NavigationModeController}
*/
@Inject
@@ -103,7 +103,7 @@
mDragDistThreshold = context.getResources().getDimensionPixelSize(
R.dimen.gestures_onehanded_drag_threshold);
final float slop = ViewConfiguration.get(context).getScaledTouchSlop();
- mSquaredSlop = slop * slop;
+ mSquaredSlop = slop * slop;
updateIsEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
index 70a81aa..51e5875 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
@@ -57,6 +57,7 @@
private final OneHandedGestureHandler mGestureHandler;
private final OneHandedTimeoutHandler mTimeoutHandler;
private final OneHandedTouchHandler mTouchHandler;
+ private final OneHandedTutorialHandler mTutorialHandler;
private final SysUiState mSysUiFlagContainer;
private Context mContext;
@@ -107,6 +108,7 @@
DisplayController displayController,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
OneHandedTouchHandler touchHandler,
+ OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
SysUiState sysUiState) {
mContext = context;
@@ -120,6 +122,7 @@
context.getContentResolver());
mTimeoutHandler = OneHandedTimeoutHandler.get();
mTouchHandler = touchHandler;
+ mTutorialHandler = tutorialHandler;
mGestureHandler = gestureHandler;
updateOneHandedEnabled();
setupGestures();
@@ -230,6 +233,7 @@
mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallback);
mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
+ mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
index 3d4338c..d616a3a 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
@@ -58,6 +58,7 @@
OneHandedTouchEventCallback mTouchEventCallback;
private boolean mIsEnabled;
+ private boolean mIsOnStopTransitioning;
private boolean mIsInOutsideRegion;
@Inject
@@ -96,8 +97,9 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
mTimeoutHandler.resetTimer();
- if (mIsInOutsideRegion) {
+ if (mIsInOutsideRegion && !mIsOnStopTransitioning) {
mTouchEventCallback.onStop();
+ mIsOnStopTransitioning = true;
}
// Reset flag for next operation
mIsInOutsideRegion = false;
@@ -146,6 +148,7 @@
@Override
public void onStopFinished(Rect bounds) {
mLastUpdatedBounds.set(bounds);
+ mIsOnStopTransitioning = false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
new file mode 100644
index 0000000..8a67da5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -0,0 +1,161 @@
+/*
+ * 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.onehanded;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages the user tutorial handling for One Handed operations, including animations synchronized
+ * with one-handed translation.
+ * Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop
+ * one handed gesture
+ */
+@Singleton
+public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable {
+ private static final String TAG = "OneHandedTutorialHandler";
+ private final Rect mLastUpdatedBounds = new Rect();
+ private final WindowManager mWindowManager;
+
+ private View mTutorialView;
+ private Point mDisplaySize = new Point();
+ private Handler mUpdateHandler;
+
+ /**
+ * Container of the tutorial panel showing at outside region when one handed starting
+ */
+ private ViewGroup mTargetViewContainer;
+ private int mTutorialAreaHeight;
+
+ private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() {
+ @Override
+ public void onTutorialAnimationUpdate(int offset) {
+ mUpdateHandler.post(() -> onAnimationUpdate(offset));
+ }
+ };
+
+ @Inject
+ public OneHandedTutorialHandler(Context context) {
+ context.getDisplay().getRealSize(mDisplaySize);
+ mUpdateHandler = new Handler();
+ mWindowManager = context.getSystemService(WindowManager.class);
+ mTargetViewContainer = new FrameLayout(context);
+ mTargetViewContainer.setClipChildren(false);
+ mTutorialAreaHeight = Math.round(mDisplaySize.y * context.getResources().getFraction(
+ R.fraction.config_one_handed_offset, 1, 1));
+ mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null);
+ mTargetViewContainer.addView(mTutorialView);
+ createOrUpdateTutorialTarget();
+ }
+
+ @Override
+ public void onStartFinished(Rect bounds) {
+ mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f));
+ }
+
+ @Override
+ public void onStopFinished(Rect bounds) {
+ mUpdateHandler.post(() -> updateFinished(
+ View.INVISIBLE, -mTargetViewContainer.getHeight()));
+ }
+
+ private void updateFinished(int visible, float finalPosition) {
+ mTargetViewContainer.setVisibility(visible);
+ mTargetViewContainer.setTranslationY(finalPosition);
+ }
+
+ /**
+ * Adds the tutorial target view to the WindowManager and update its layout, so it's ready
+ * to be animated in.
+ */
+ private void createOrUpdateTutorialTarget() {
+ mUpdateHandler.post(() -> {
+ if (!mTargetViewContainer.isAttachedToWindow()) {
+ mTargetViewContainer.setVisibility(View.INVISIBLE);
+
+ try {
+ mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
+ } catch (IllegalStateException e) {
+ // This shouldn't happen, but if the target is already added, just update its
+ // layout params.
+ mWindowManager.updateViewLayout(
+ mTargetViewContainer, getTutorialTargetLayoutParams());
+ }
+ } else {
+ mWindowManager.updateViewLayout(mTargetViewContainer,
+ getTutorialTargetLayoutParams());
+ }
+ });
+ }
+
+ OneHandedAnimationCallback getAnimationCallback() {
+ return mAnimationCallback;
+ }
+
+ /**
+ * Returns layout params for the dismiss target, using the latest display metrics.
+ */
+ private WindowManager.LayoutParams getTutorialTargetLayoutParams() {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ mDisplaySize.x, mTutorialAreaHeight, 0, 0,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setFitInsetsTypes(0 /* types */);
+ lp.setTitle("one-handed-tutorial-overlay");
+
+ return lp;
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ final String innerPrefix = " ";
+ pw.println(TAG + "states: ");
+ pw.print(innerPrefix + "mLastUpdatedBounds=");
+ pw.println(mLastUpdatedBounds);
+ }
+
+ private void onAnimationUpdate(float value) {
+ mTargetViewContainer.setVisibility(View.VISIBLE);
+ mTargetViewContainer.setTransitionGroup(true);
+ mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 5f37cc45..df61fd1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -65,10 +65,6 @@
}
}
- public void growRecents() {
- mImpl.growRecents();
- }
-
@Override
public void showRecentApps(boolean triggeredFromAltTab) {
// Ensure the device has been provisioned before allowing the user to interact with
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index eb72312..4007abb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -16,559 +16,127 @@
package com.android.systemui.stackdivider;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.wm.shell.common.DisplayChangeController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Optional;
import java.util.function.Consumer;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* Controls the docked stack divider.
*/
@Singleton
-public class Divider extends SystemUI implements DividerView.DividerCallbacks,
- DisplayController.OnDisplaysChangedListener {
- private static final String TAG = "Divider";
+public class Divider extends SystemUI {
+ private final KeyguardStateController mKeyguardStateController;
+ private final DividerController mDividerController;
- static final boolean DEBUG = false;
-
- static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
- private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
-
- private DividerWindowManager mWindowManager;
- private DividerView mView;
- private final DividerState mDividerState = new DividerState();
- private boolean mVisible = false;
- private boolean mMinimized = false;
- private boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
- private ForcedResizableInfoActivityController mForcedResizableController;
- private SystemWindows mSystemWindows;
- private DisplayController mDisplayController;
- private DisplayImeController mImeController;
- final TransactionPool mTransactionPool;
-
- // Keeps track of real-time split geometry including snap positions and ime adjustments
- private SplitDisplayLayout mSplitLayout;
-
- // Transient: this contains the layout calculated for a new rotation requested by WM. This is
- // kept around so that we can wait for a matching configuration change and then use the exact
- // layout that we sent back to WM.
- private SplitDisplayLayout mRotateSplitLayout;
-
- private Handler mHandler;
- private KeyguardStateController mKeyguardStateController;
-
- private WindowManagerProxy mWindowManagerProxy;
-
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
-
- private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
-
- private DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
- return;
- }
- WindowContainerTransaction t = new WindowContainerTransaction();
- DisplayLayout displayLayout =
- new DisplayLayout(mDisplayController.getDisplayLayout(display));
- SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
- sdl.rotateTo(toRotation);
- mRotateSplitLayout = sdl;
- final int position = isDividerVisible()
- ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : mView.getCurrentPosition())
- // snap resets to middle target when not in split-mode
- : sdl.getSnapAlgorithm().getMiddleTarget().position;
- DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
- final DividerSnapAlgorithm.SnapTarget target =
- snap.calculateNonDismissingSnapTarget(position);
- sdl.resizeSplits(target.position, t);
-
- if (isSplitActive() && mHomeStackResizable) {
- WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
- }
- if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
- // Because sync transactions are serialized, its possible for an "older"
- // bounds-change to get applied after a screen rotation. In that case, we
- // want to actually defer on that rather than apply immediately. Of course,
- // this means that the bounds may not change until after the rotation so
- // the user might see some artifacts. This should be rare.
- Slog.w(TAG, "Screen rotated while other operations were pending, this may"
- + " result in some graphical artifacts.");
- } else {
- wct.merge(t, true /* transfer */);
- }
- };
-
- private final DividerImeController mImePositionProcessor;
-
- private TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || !mSplits.isSplitScreenSupported()) {
- return;
- }
-
- if (isMinimized()) {
- onUndockingTask();
- }
- }
- };
-
- public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, Handler handler,
- KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
+ Divider(Context context, DividerController dividerController,
+ KeyguardStateController keyguardStateController) {
super(context);
- mDisplayController = displayController;
- mSystemWindows = systemWindows;
- mImeController = imeController;
- mHandler = handler;
+ mDividerController = dividerController;
mKeyguardStateController = keyguardStateController;
- mRecentsOptionalLazy = recentsOptionalLazy;
- mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
- mTransactionPool = transactionPool;
- mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
- mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
}
@Override
public void start() {
- mWindowManager = new DividerWindowManager(mSystemWindows);
- mDisplayController.addDisplayWindowListener(this);
+ mDividerController.start();
// Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
// everything, it is actually transparent except for notifications, so we still need to
// hide any surfaces that are below it.
// TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
- public void onUnlockedChanged() {
-
- }
-
- @Override
public void onKeyguardShowingChanged() {
- if (!isSplitActive() || mView == null) {
- return;
- }
- mView.setHidden(mKeyguardStateController.isShowing());
- if (!mKeyguardStateController.isShowing()) {
- mImePositionProcessor.updateAdjustForIme();
- }
- }
-
- @Override
- public void onKeyguardFadingAwayChanged() {
-
+ mDividerController.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
}
});
// Don't initialize the divider or anything until we get the default display.
- }
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- mImeController.addPositionProcessor(mImePositionProcessor);
- mDisplayController.addDisplayChangingController(mRotationController);
- if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
- removeDivider();
- return;
- }
- try {
- mSplits.init();
- // Set starting tile bounds based on middle target
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mSplitLayout.resizeSplits(midPos, tct);
- WindowOrganizer.applyTransaction(tct);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to register docked stack listener", e);
- removeDivider();
- return;
- }
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mActivityRestartListener);
- }
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !mDividerController.isSplitScreenSupported()) {
+ return;
+ }
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
- return;
- }
- mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- if (mRotateSplitLayout == null) {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- mSplitLayout.resizeSplits(midPos, tct);
- WindowOrganizer.applyTransaction(tct);
- } else if (mSplitLayout.mDisplayLayout.rotation()
- == mRotateSplitLayout.mDisplayLayout.rotation()) {
- mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
- mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
- mRotateSplitLayout = null;
- }
- if (isSplitActive()) {
- update(newConfig);
- }
- }
-
- Handler getHandler() {
- return mHandler;
- }
-
- public DividerView getView() {
- return mView;
- }
-
- public boolean isMinimized() {
- return mMinimized;
- }
-
- public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- /** {@code true} if this is visible */
- public boolean isDividerVisible() {
- return mView != null && mView.getVisibility() == View.VISIBLE;
- }
-
- /**
- * This indicates that at-least one of the splits has content. This differs from
- * isDividerVisible because the divider is only visible once *everything* is in split mode
- * while this only cares if some things are (eg. while entering/exiting as well).
- */
- private boolean isSplitActive() {
- return mSplits.mPrimary != null && mSplits.mSecondary != null
- && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
- || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
- }
-
- private void addDivider(Configuration configuration) {
- Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
- mView = (DividerView)
- LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
- DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor, mWindowManagerProxy);
- mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
- final int size = dctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
- final int width = landscape ? size : displayLayout.width();
- final int height = landscape ? displayLayout.height() : size;
- mWindowManager.add(mView, width, height, mContext.getDisplayId());
- }
-
- private void removeDivider() {
- if (mView != null) {
- mView.onDividerRemoved();
- }
- mWindowManager.remove();
- }
-
- private void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mKeyguardStateController.isShowing();
-
- removeDivider();
- addDivider(configuration);
-
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
- }
-
- void onTaskVanished() {
- mHandler.post(this::removeDivider);
- }
-
- private void updateVisibility(final boolean visible) {
- if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
- if (mVisible != visible) {
- mVisible = visible;
- mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-
- if (visible) {
- mView.enterSplitMode(mHomeStackResizable);
- // Update state because animations won't finish.
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
-
- } else {
- mView.exitSplitMode();
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
- }
- // Notify existence listeners
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.removeIf(wf -> {
- Consumer<Boolean> l = wf.get();
- if (l != null) l.accept(visible);
- return l == null;
- });
- }
- }
- }
-
- /** Switch to minimized state if appropriate */
- public void setMinimized(final boolean minimized) {
- if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
- mHandler.post(() -> {
- if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
- if (!mVisible) {
- return;
- }
- setHomeMinimized(minimized, mHomeStackResizable);
- });
- }
-
- private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
- if (DEBUG) {
- Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
- + mHomeStackResizable + "->" + homeStackResizable
- + " split:" + isDividerVisible());
- }
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final boolean minimizedChanged = mMinimized != minimized;
- // Update minimized state
- if (minimizedChanged) {
- mMinimized = minimized;
- }
- // Always set this because we could be entering split when mMinimized is already true
- wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
- boolean onlyFocusable = true;
-
- // Update home-stack resizability
- final boolean homeResizableChanged = mHomeStackResizable != homeStackResizable;
- if (homeResizableChanged) {
- mHomeStackResizable = homeStackResizable;
- if (isDividerVisible()) {
- WindowManagerProxy.applyHomeTasksMinimized(
- mSplitLayout, mSplits.mSecondary.token, wct);
- onlyFocusable = false;
- }
- }
-
- // Sync state to DividerView if it exists.
- if (mView != null) {
- final int displayId = mView.getDisplay() != null
- ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
- // pause ime here (before updateMinimizedDockedStack)
- if (mMinimized) {
- mImePositionProcessor.pause(displayId);
- }
- if (minimizedChanged || homeResizableChanged) {
- // This conflicts with IME adjustment, so only call it when things change.
- mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
- }
- if (!mMinimized) {
- // afterwards so it can end any animations started in view
- mImePositionProcessor.resume(displayId);
- }
- }
- updateTouchable();
- if (onlyFocusable) {
- // If we are only setting focusability, a sync transaction isn't necessary (in fact it
- // can interrupt other animations), so see if it can be submitted on pending instead.
- if (!mSplits.mDivider.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
- WindowOrganizer.applyTransaction(wct);
- }
- } else {
- mWindowManagerProxy.applySyncTransaction(wct);
- }
- }
-
- void setAdjustedForIme(boolean adjustedForIme) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- mAdjustedForIme = adjustedForIme;
- updateTouchable();
- }
-
- private void updateTouchable() {
- mWindowManager.setTouchable(!mAdjustedForIme);
- }
-
- /**
- * Workaround for b/62528361, at the time recents has drawn, it may happen before a
- * configuration change to the Divider, and internally, the event will be posted to the
- * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
- * register the event handler here and proxy the event to the current DividerView.
- */
- public void onRecentsDrawn() {
- if (mView != null) {
- mView.onRecentsDrawn();
- }
- }
-
- public void onUndockingTask() {
- if (mView != null) {
- mView.onUndockingTask();
- }
- }
-
- public void onDockedFirstAnimationFrame() {
- if (mView != null) {
- mView.onDockedFirstAnimationFrame();
- }
- }
-
- public void onDockedTopTask() {
- if (mView != null) {
- mView.onDockedTopTask();
- }
- }
-
- public void onAppTransitionFinished() {
- if (mView == null) {
- return;
- }
- mForcedResizableController.onAppTransitionFinished();
- }
-
- @Override
- public void onDraggingStart() {
- mForcedResizableController.onDraggingStart();
- }
-
- @Override
- public void onDraggingEnd() {
- mForcedResizableController.onDraggingEnd();
- }
-
- @Override
- public void growRecents() {
- mRecentsOptionalLazy.ifPresent(recentsLazy -> recentsLazy.get().growRecents());
+ if (mDividerController.isMinimized()) {
+ onUndockingTask();
+ }
+ }
+ }
+ );
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" mVisible="); pw.println(mVisible);
- pw.print(" mMinimized="); pw.println(mMinimized);
- pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
+ mDividerController.dump(pw);
}
- long getAnimDuration() {
- float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- com.android.internal.R.dimen
- .config_appTransitionAnimationDurationScaleDefault));
- final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
- return (long) (transitionDuration * transitionScale);
+ /** Switch to minimized state if appropriate. */
+ public void setMinimized(final boolean minimized) {
+ mDividerController.setMinimized(minimized);
}
- /** Register a listener that gets called whenever the existence of the divider changes */
- public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- listener.accept(isDividerVisible());
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.add(new WeakReference<>(listener));
- }
+ public boolean isMinimized() {
+ return mDividerController.isMinimized();
}
- void startEnterSplit() {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- // Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ public boolean isHomeStackResizable() {
+ return mDividerController.isHomeStackResizable();
}
- void startDismissSplit() {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
- updateVisibility(false /* visible */);
- mMinimized = false;
- removeDivider();
- mImePositionProcessor.reset();
+ /** Callback for undocking task. */
+ public void onUndockingTask() {
+ mDividerController.onUndockingTask();
}
- void ensureMinimizedSplit() {
- setHomeMinimized(true /* minimized */, mHomeStackResizable);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode yet, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " entering split mode with minimized=true");
- }
- updateVisibility(true /* visible */);
- }
+ public void onRecentsDrawn() {
+ mDividerController.onRecentsDrawn();
}
- void ensureNormalSplit() {
- setHomeMinimized(false /* minimized */, mHomeStackResizable);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " enter split mode unminimized ");
- }
- updateVisibility(true /* visible */);
- }
+ public void onDockedFirstAnimationFrame() {
+ mDividerController.onDockedFirstAnimationFrame();
}
- SplitDisplayLayout getSplitLayout() {
- return mSplitLayout;
+ public void onDockedTopTask() {
+ mDividerController.onDockedTopTask();
}
- WindowManagerProxy getWmProxy() {
- return mWindowManagerProxy;
+ public void onAppTransitionFinished() {
+ mDividerController.onAppTransitionFinished();
+ }
+
+ public DividerView getView() {
+ return mDividerController.getDividerView();
}
/** @return the container token for the secondary split root task. */
public WindowContainerToken getSecondaryRoot() {
- if (mSplits == null || mSplits.mSecondary == null) {
- return null;
- }
- return mSplits.mSecondary.token;
+ return mDividerController.getSecondaryRoot();
+ }
+
+ /** Register a listener that gets called whenever the existence of the divider changes */
+ public void registerInSplitScreenListener(Consumer<Boolean> listener) {
+ mDividerController.registerInSplitScreenListener(listener);
+ }
+
+ /** {@code true} if this is visible */
+ public boolean isDividerVisible() {
+ return mDividerController.isDividerVisible();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
new file mode 100644
index 0000000..81649f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
@@ -0,0 +1,516 @@
+/*
+ * 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.stackdivider;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+import android.window.WindowOrganizer;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.systemui.R;
+import com.android.wm.shell.common.DisplayChangeController;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Controls the docked stack divider.
+ */
+public class DividerController implements DividerView.DividerCallbacks,
+ DisplayController.OnDisplaysChangedListener {
+ static final boolean DEBUG = false;
+ private static final String TAG = "Divider";
+
+ static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ private DividerWindowManager mWindowManager;
+ private DividerView mView;
+ private final DividerState mDividerState = new DividerState();
+ private boolean mVisible = false;
+ private boolean mMinimized = false;
+ private boolean mAdjustedForIme = false;
+ private boolean mHomeStackResizable = false;
+ private ForcedResizableInfoActivityController mForcedResizableController;
+ private SystemWindows mSystemWindows;
+ private DisplayController mDisplayController;
+ private DisplayImeController mImeController;
+ final TransactionPool mTransactionPool;
+
+ // Keeps track of real-time split geometry including snap positions and ime adjustments
+ private SplitDisplayLayout mSplitLayout;
+
+ // Transient: this contains the layout calculated for a new rotation requested by WM. This is
+ // kept around so that we can wait for a matching configuration change and then use the exact
+ // layout that we sent back to WM.
+ private SplitDisplayLayout mRotateSplitLayout;
+
+ private final Handler mHandler;
+ private final WindowManagerProxy mWindowManagerProxy;
+
+ private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
+ new ArrayList<>();
+
+ private final SplitScreenTaskOrganizer mSplits;
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController;
+ private final DividerImeController mImePositionProcessor;
+ private final Context mContext;
+ private boolean mIsKeyguardShowing;
+
+ public DividerController(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController imeController, Handler handler, TransactionPool transactionPool) {
+ mContext = context;
+ mDisplayController = displayController;
+ mSystemWindows = systemWindows;
+ mImeController = imeController;
+ mHandler = handler;
+ mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
+ mTransactionPool = transactionPool;
+ mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
+ mSplits = new SplitScreenTaskOrganizer(this);
+ mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
+ mRotationController =
+ (display, fromRotation, toRotation, wct) -> {
+ if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
+ return;
+ }
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ DisplayLayout displayLayout =
+ new DisplayLayout(mDisplayController.getDisplayLayout(display));
+ SplitDisplayLayout sdl =
+ new SplitDisplayLayout(mContext, displayLayout, mSplits);
+ sdl.rotateTo(toRotation);
+ mRotateSplitLayout = sdl;
+ final int position = isDividerVisible()
+ ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
+ : mView.getCurrentPosition())
+ // snap resets to middle target when not in split-mode
+ : sdl.getSnapAlgorithm().getMiddleTarget().position;
+ DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
+ final DividerSnapAlgorithm.SnapTarget target =
+ snap.calculateNonDismissingSnapTarget(position);
+ sdl.resizeSplits(target.position, t);
+
+ if (isSplitActive() && mHomeStackResizable) {
+ WindowManagerProxy
+ .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
+ }
+ if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
+ // Because sync transactions are serialized, its possible for an "older"
+ // bounds-change to get applied after a screen rotation. In that case, we
+ // want to actually defer on that rather than apply immediately. Of course,
+ // this means that the bounds may not change until after the rotation so
+ // the user might see some artifacts. This should be rare.
+ Slog.w(TAG, "Screen rotated while other operations were pending, this may"
+ + " result in some graphical artifacts.");
+ } else {
+ wct.merge(t, true /* transfer */);
+ }
+ };
+ }
+
+ /** Inits the divider service. */
+ public void start() {
+ mWindowManager = new DividerWindowManager(mSystemWindows);
+ mDisplayController.addDisplayWindowListener(this);
+ // Don't initialize the divider or anything until we get the default display.
+ }
+
+ /** Returns {@code true} if split screen is supported on the device. */
+ public boolean isSplitScreenSupported() {
+ return mSplits.isSplitScreenSupported();
+ }
+
+ /** Called when keyguard showing state changed. */
+ public void onKeyguardShowingChanged(boolean isShowing) {
+ if (!isSplitActive() || mView == null) {
+ return;
+ }
+ mView.setHidden(isShowing);
+ if (!isShowing) {
+ mImePositionProcessor.updateAdjustForIme();
+ }
+ mIsKeyguardShowing = isShowing;
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ mImeController.addPositionProcessor(mImePositionProcessor);
+ mDisplayController.addDisplayChangingController(mRotationController);
+ if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
+ removeDivider();
+ return;
+ }
+ try {
+ mSplits.init();
+ // Set starting tile bounds based on middle target
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ mSplitLayout.resizeSplits(midPos, tct);
+ WindowOrganizer.applyTransaction(tct);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to register docked stack listener", e);
+ removeDivider();
+ return;
+ }
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ if (mRotateSplitLayout == null) {
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ mSplitLayout.resizeSplits(midPos, tct);
+ WindowOrganizer.applyTransaction(tct);
+ } else if (mSplitLayout.mDisplayLayout.rotation()
+ == mRotateSplitLayout.mDisplayLayout.rotation()) {
+ mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
+ mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
+ mRotateSplitLayout = null;
+ }
+ if (isSplitActive()) {
+ update(newConfig);
+ }
+ }
+
+ /** Posts task to handler dealing with divider. */
+ void post(Runnable task) {
+ mHandler.post(task);
+ }
+
+ /** Returns {@link DividerView}. */
+ public DividerView getDividerView() {
+ return mView;
+ }
+
+ /** Returns {@code true} if one of the split screen is in minimized mode. */
+ public boolean isMinimized() {
+ return mMinimized;
+ }
+
+ public boolean isHomeStackResizable() {
+ return mHomeStackResizable;
+ }
+
+ /** Returns {@code true} if the divider is visible. */
+ public boolean isDividerVisible() {
+ return mView != null && mView.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * This indicates that at-least one of the splits has content. This differs from
+ * isDividerVisible because the divider is only visible once *everything* is in split mode
+ * while this only cares if some things are (eg. while entering/exiting as well).
+ */
+ private boolean isSplitActive() {
+ return mSplits.mPrimary != null && mSplits.mSecondary != null
+ && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
+ || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ private void addDivider(Configuration configuration) {
+ Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
+ mView = (DividerView)
+ LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
+ DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
+ mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
+ mImePositionProcessor, mWindowManagerProxy);
+ mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
+ final int size = dctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_thickness);
+ final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
+ final int width = landscape ? size : displayLayout.width();
+ final int height = landscape ? displayLayout.height() : size;
+ mWindowManager.add(mView, width, height, mContext.getDisplayId());
+ }
+
+ private void removeDivider() {
+ if (mView != null) {
+ mView.onDividerRemoved();
+ }
+ mWindowManager.remove();
+ }
+
+ private void update(Configuration configuration) {
+ final boolean isDividerHidden = mView != null && mIsKeyguardShowing;
+
+ removeDivider();
+ addDivider(configuration);
+
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
+ updateTouchable();
+ }
+ mView.setHidden(isDividerHidden);
+ }
+
+ void onTaskVanished() {
+ mHandler.post(this::removeDivider);
+ }
+
+ private void updateVisibility(final boolean visible) {
+ if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
+ if (mVisible != visible) {
+ mVisible = visible;
+ mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+ if (visible) {
+ mView.enterSplitMode(mHomeStackResizable);
+ // Update state because animations won't finish.
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
+
+ } else {
+ mView.exitSplitMode();
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
+ }
+ // Notify existence listeners
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.removeIf(wf -> {
+ Consumer<Boolean> l = wf.get();
+ if (l != null) l.accept(visible);
+ return l == null;
+ });
+ }
+ }
+ }
+
+ /** Switch to minimized state if appropriate. */
+ public void setMinimized(final boolean minimized) {
+ if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
+ mHandler.post(() -> {
+ if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
+ if (!mVisible) {
+ return;
+ }
+ setHomeMinimized(minimized);
+ });
+ }
+
+ private void setHomeMinimized(final boolean minimized) {
+ if (DEBUG) {
+ Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
+ + mHomeStackResizable + " split:" + isDividerVisible());
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ final boolean minimizedChanged = mMinimized != minimized;
+ // Update minimized state
+ if (minimizedChanged) {
+ mMinimized = minimized;
+ }
+ // Always set this because we could be entering split when mMinimized is already true
+ wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+ // Sync state to DividerView if it exists.
+ if (mView != null) {
+ final int displayId = mView.getDisplay() != null
+ ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
+ // pause ime here (before updateMinimizedDockedStack)
+ if (mMinimized) {
+ mImePositionProcessor.pause(displayId);
+ }
+ if (minimizedChanged) {
+ // This conflicts with IME adjustment, so only call it when things change.
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
+ }
+ if (!mMinimized) {
+ // afterwards so it can end any animations started in view
+ mImePositionProcessor.resume(displayId);
+ }
+ }
+ updateTouchable();
+
+ // If we are only setting focusability, a sync transaction isn't necessary (in fact it
+ // can interrupt other animations), so see if it can be submitted on pending instead.
+ if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) {
+ WindowOrganizer.applyTransaction(wct);
+ }
+ }
+
+ void setAdjustedForIme(boolean adjustedForIme) {
+ if (mAdjustedForIme == adjustedForIme) {
+ return;
+ }
+ mAdjustedForIme = adjustedForIme;
+ updateTouchable();
+ }
+
+ private void updateTouchable() {
+ mWindowManager.setTouchable(!mAdjustedForIme);
+ }
+
+ /**
+ * Workaround for b/62528361, at the time recents has drawn, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ public void onRecentsDrawn() {
+ if (mView != null) {
+ mView.onRecentsDrawn();
+ }
+ }
+
+ /** Called when there's a task undocking. */
+ public void onUndockingTask() {
+ if (mView != null) {
+ mView.onUndockingTask();
+ }
+ }
+
+ /** Called when the first docked animation frame rendered. */
+ public void onDockedFirstAnimationFrame() {
+ if (mView != null) {
+ mView.onDockedFirstAnimationFrame();
+ }
+ }
+
+ /** Called when top task docked. */
+ public void onDockedTopTask() {
+ if (mView != null) {
+ mView.onDockedTopTask();
+ }
+ }
+
+ /** Called when app transition finished. */
+ public void onAppTransitionFinished() {
+ if (mView == null) {
+ return;
+ }
+ mForcedResizableController.onAppTransitionFinished();
+ }
+
+ @Override
+ public void onDraggingStart() {
+ mForcedResizableController.onDraggingStart();
+ }
+
+ @Override
+ public void onDraggingEnd() {
+ mForcedResizableController.onDraggingEnd();
+ }
+
+ /** Dumps current status of Divider.*/
+ public void dump(PrintWriter pw) {
+ pw.print(" mVisible="); pw.println(mVisible);
+ pw.print(" mMinimized="); pw.println(mMinimized);
+ pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
+ }
+
+ long getAnimDuration() {
+ float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mContext.getResources().getFloat(
+ com.android.internal.R.dimen
+ .config_appTransitionAnimationDurationScaleDefault));
+ final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
+ return (long) (transitionDuration * transitionScale);
+ }
+
+ /** Registers listener that gets called whenever the existence of the divider changes. */
+ public void registerInSplitScreenListener(Consumer<Boolean> listener) {
+ listener.accept(isDividerVisible());
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.add(new WeakReference<>(listener));
+ }
+ }
+
+ void startEnterSplit() {
+ update(mDisplayController.getDisplayContext(
+ mContext.getDisplayId()).getResources().getConfiguration());
+ // Set resizable directly here because applyEnterSplit already resizes home stack.
+ mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ }
+
+ void startDismissSplit() {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ updateVisibility(false /* visible */);
+ mMinimized = false;
+ removeDivider();
+ mImePositionProcessor.reset();
+ }
+
+ void ensureMinimizedSplit() {
+ setHomeMinimized(true /* minimized */);
+ if (mView != null && !isDividerVisible()) {
+ // Wasn't in split-mode yet, so enter now.
+ if (DEBUG) {
+ Slog.d(TAG, " entering split mode with minimized=true");
+ }
+ updateVisibility(true /* visible */);
+ }
+ }
+
+ void ensureNormalSplit() {
+ setHomeMinimized(false /* minimized */);
+ if (mView != null && !isDividerVisible()) {
+ // Wasn't in split-mode, so enter now.
+ if (DEBUG) {
+ Slog.d(TAG, " enter split mode unminimized ");
+ }
+ updateVisibility(true /* visible */);
+ }
+ }
+
+ SplitDisplayLayout getSplitLayout() {
+ return mSplitLayout;
+ }
+
+ WindowManagerProxy getWmProxy() {
+ return mWindowManagerProxy;
+ }
+
+ /** @return the container token for the secondary split root task. */
+ public WindowContainerToken getSecondaryRoot() {
+ if (mSplits == null || mSplits.mSecondary == null) {
+ return null;
+ }
+ return mSplits.mSecondary.token;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index d5f7b39..a10242a 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -34,7 +34,7 @@
/**
* View for the handle in the docked stack divider.
*/
-public class DividerHandleView extends View {
+class DividerHandleView extends View {
private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
= new Property<DividerHandleView, Integer>(Integer.class, "width") {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 84ec387..c915f07 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -38,7 +38,7 @@
class DividerImeController implements DisplayImeController.ImePositionProcessor {
private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
@@ -100,15 +100,15 @@
}
private DividerView getView() {
- return mSplits.mDivider.getView();
+ return mSplits.mDividerController.getDividerView();
}
private SplitDisplayLayout getLayout() {
- return mSplits.mDivider.getSplitLayout();
+ return mSplits.mDividerController.getSplitLayout();
}
private boolean isDividerVisible() {
- return mSplits.mDivider.isDividerVisible();
+ return mSplits.mDividerController.isDividerVisible();
}
private boolean getSecondaryHasFocus(int displayId) {
@@ -151,7 +151,7 @@
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mDivider.isMinimized();
+ && !mSplits.mDividerController.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -236,7 +236,7 @@
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- if (!mSplits.mDivider.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
+ if (!mSplits.mDividerController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
WindowOrganizer.applyTransaction(wct);
}
}
@@ -250,7 +250,7 @@
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
}
}
- mSplits.mDivider.setAdjustedForIme(mTargetShown && !mPaused);
+ mSplits.mDividerController.setAdjustedForIme(mTargetShown && !mPaused);
}
public void updateAdjustForIme() {
@@ -343,10 +343,12 @@
mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancel = false;
+
@Override
public void onAnimationCancel(Animator animation) {
mCancel = true;
}
+
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
@@ -400,7 +402,8 @@
mTargetAdjusted = mPausedTargetAdjusted;
updateDimTargets();
final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mDivider.isMinimized() && view != null) {
+ if ((mTargetAdjusted != mAdjusted) && !mSplits.mDividerController.isMinimized()
+ && view != null) {
// End unminimize animations since they conflict with adjustment animations.
view.finishAnimations();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
index c24431c..db0aef8 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
@@ -20,18 +20,14 @@
import android.os.Handler;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
-import java.util.Optional;
-
import javax.inject.Singleton;
-import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -42,11 +38,12 @@
public class DividerModule {
@Singleton
@Provides
- static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, @Main Handler handler,
+ static Divider provideDivider(Context context, DisplayController displayController,
+ SystemWindows systemWindows, DisplayImeController imeController, @Main Handler handler,
KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
- return new Divider(context, recentsOptionalLazy, displayController, systemWindows,
- imeController, handler, keyguardStateController, transactionPool);
+ // TODO(b/161116823): fetch DividerProxy from WM shell lib.
+ DividerController dividerController = new DividerController(context, displayController,
+ systemWindows, imeController, handler, transactionPool);
+ return new Divider(context, dividerController, keyguardStateController);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
index 3a5c61e..8e79d51 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
@@ -21,6 +21,5 @@
*/
public class DividerState {
public boolean animateAfterRecentsDrawn;
- public boolean growAfterRecentsDrawn;
public float mRatioPositionBeforeMinimized;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index b6c6afd..e5c02d6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -76,12 +76,11 @@
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
private static final String TAG = "DividerView";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
public interface DividerCallbacks {
void onDraggingStart();
void onDraggingEnd();
- void growRecents();
}
static final long TOUCH_ANIMATION_DURATION = 150;
@@ -148,7 +147,6 @@
private DividerCallbacks mCallback;
private final AnimationHandler mAnimationHandler = new AnimationHandler();
- private boolean mGrowRecents;
private ValueAnimator mCurrentAnimator;
private boolean mEntranceAnimationRunning;
private boolean mExitAnimationRunning;
@@ -304,7 +302,6 @@
R.dimen.docked_stack_divider_lift_elevation);
mLongPressEntraceAnimDuration = getResources().getInteger(
R.integer.long_press_dock_anim_duration);
- mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
boolean landscape = getResources().getConfiguration().orientation
@@ -437,17 +434,17 @@
releaseBackground();
}
- public void stopDragging(int position, SnapTarget target, long duration,
+ private void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator) {
stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
}
- public void stopDragging(int position, SnapTarget target, long duration,
+ private void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator, long endDelay) {
stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
}
- public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
+ private void stopDragging(int position, SnapTarget target, long duration, long startDelay,
long endDelay, Interpolator interpolator) {
mHandle.setTouching(false, true /* animate */);
flingTo(position, target, duration, startDelay, endDelay, interpolator);
@@ -1319,39 +1316,11 @@
mBackground.getRight(), mBackground.getBottom(), Op.UNION);
}
- /**
- * Checks whether recents will grow when invoked. This happens in multi-window when recents is
- * very small. When invoking recents, we shrink the docked stack so recents has more space.
- *
- * @return the position of the divider when recents grows, or
- * {@link #INVALID_RECENTS_GROW_TARGET} if recents won't grow
- */
- public int growsRecents() {
- boolean result = mGrowRecents
- && mDockSide == WindowManager.DOCKED_TOP
- && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
- if (result) {
- return getSnapAlgorithm().getMiddleTarget().position;
- } else {
- return INVALID_RECENTS_GROW_TARGET;
- }
- }
-
- void onRecentsActivityStarting() {
- if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
- && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
- && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
- mState.growAfterRecentsDrawn = true;
- startDragging(false /* animate */, false /* touching */);
- }
- }
-
void onDockedFirstAnimationFrame() {
saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
}
void onDockedTopTask() {
- mState.growAfterRecentsDrawn = false;
mState.animateAfterRecentsDrawn = true;
startDragging(false /* animate */, false /* touching */);
updateDockSide();
@@ -1377,15 +1346,6 @@
200 /* endDelay */);
});
}
- if (mState.growAfterRecentsDrawn) {
- mState.growAfterRecentsDrawn = false;
- updateDockSide();
- if (mCallback != null) {
- mCallback.growRecents();
- }
- stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
- Interpolators.FAST_OUT_SLOW_IN);
- }
}
void onUndockingTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index db7996e..f412cc0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -75,7 +75,8 @@
}
}
- public ForcedResizableInfoActivityController(Context context, Divider divider) {
+ public ForcedResizableInfoActivityController(Context context,
+ DividerController dividerController) {
mContext = context;
ActivityManagerWrapper.getInstance().registerTaskStackListener(
new TaskStackChangeListener() {
@@ -95,7 +96,7 @@
activityLaunchOnSecondaryDisplayFailed();
}
});
- divider.registerInSplitScreenListener(mDockedStackExistsListener);
+ dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
}
public void onAppTransitionFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 7a313dc..ef5e8a1 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -35,7 +35,7 @@
class SplitScreenTaskOrganizer extends TaskOrganizer {
private static final String TAG = "SplitScreenTaskOrg";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
RunningTaskInfo mPrimary;
RunningTaskInfo mSecondary;
@@ -44,13 +44,13 @@
SurfaceControl mPrimaryDim;
SurfaceControl mSecondaryDim;
Rect mHomeBounds = new Rect();
- final Divider mDivider;
+ final DividerController mDividerController;
private boolean mSplitScreenSupported = false;
final SurfaceSession mSurfaceSession = new SurfaceSession();
- SplitScreenTaskOrganizer(Divider divider) {
- mDivider = divider;
+ SplitScreenTaskOrganizer(DividerController dividerController) {
+ mDividerController = dividerController;
}
void init() throws RemoteException {
@@ -75,11 +75,11 @@
}
SurfaceControl.Transaction getTransaction() {
- return mDivider.mTransactionPool.acquire();
+ return mDividerController.mTransactionPool.acquire();
}
void releaseTransaction(SurfaceControl.Transaction t) {
- mDivider.mTransactionPool.release(t);
+ mDividerController.mTransactionPool.release(t);
}
@Override
@@ -140,7 +140,7 @@
t.apply();
releaseTransaction(t);
- mDivider.onTaskVanished();
+ mDividerController.onTaskVanished();
}
}
}
@@ -150,7 +150,7 @@
if (taskInfo.displayId != DEFAULT_DISPLAY) {
return;
}
- mDivider.getHandler().post(() -> handleTaskInfoChanged(taskInfo));
+ mDividerController.post(() -> handleTaskInfoChanged(taskInfo));
}
/**
@@ -169,7 +169,7 @@
}
final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDivider.isHomeStackResizable());
+ && mDividerController.isHomeStackResizable());
final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
if (info.token.asBinder() == mPrimary.token.asBinder()) {
@@ -181,7 +181,7 @@
final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDivider.isHomeStackResizable());
+ && mDividerController.isHomeStackResizable());
if (DEBUG) {
Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
}
@@ -197,14 +197,14 @@
Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ " " + mSecondary.topActivityType);
}
- if (mDivider.isDividerVisible()) {
+ if (mDividerController.isDividerVisible()) {
// Was in split-mode, which means we are leaving split, so continue that.
// This happens when the stack in the primary-split is dismissed.
if (DEBUG) {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mDivider.startDismissSplit();
+ mDividerController.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
@@ -213,15 +213,15 @@
if (DEBUG) {
Log.d(TAG, " was not in split, but primary is populated, so enter it");
}
- mDivider.startEnterSplit();
+ mDividerController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
- mDivider.ensureMinimizedSplit();
+ mDividerController.ensureMinimizedSplit();
} else {
// Both splits are populated by normal activities, so make sure we aren't minimized.
- mDivider.ensureNormalSplit();
+ mDividerController.ensureNormalSplit();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
index 6812f62..f2500e5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -33,7 +33,7 @@
* Helper for serializing sync-transactions and corresponding callbacks.
*/
class SyncTransactionQueue {
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 2b36812..82b10bd 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -50,7 +50,7 @@
/**
* Proxy to simplify calls into window manager/activity manager
*/
-public class WindowManagerProxy {
+class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index aba9e10..e1ff8724 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar.notification;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
@@ -24,14 +23,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -41,7 +37,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
@@ -54,11 +49,11 @@
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
@@ -147,8 +142,6 @@
private final NotificationRankingManager mRankingManager;
private final FeatureFlags mFeatureFlags;
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
- private final HeadsUpManager mHeadsUpManager;
- private final StatusBarStateController mStatusBarStateController;
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
@@ -213,8 +206,7 @@
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
ForegroundServiceDismissalFeatureController fgsFeatureController,
- HeadsUpManager headsUpManager,
- StatusBarStateController statusBarStateController
+ IStatusBarService statusBarService
) {
mLogger = logger;
mGroupManager = groupManager;
@@ -225,11 +217,7 @@
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
mLeakDetector = leakDetector;
mFgsFeatureController = fgsFeatureController;
- mHeadsUpManager = headsUpManager;
- mStatusBarStateController = statusBarStateController;
-
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
+ mStatusBarService = statusBarService;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -284,16 +272,23 @@
}
/**
- * Requests a notification to be removed.
+ * User requests a notification to be removed.
*
* @param n the notification to remove.
* @param reason why it is being removed e.g. {@link NotificationListenerService#REASON_CANCEL},
* or 0 if unknown.
*/
- public void performRemoveNotification(StatusBarNotification n, int reason) {
- final NotificationVisibility nv = obtainVisibility(n.getKey());
+ public void performRemoveNotification(
+ StatusBarNotification n,
+ @NonNull DismissedByUserStats stats,
+ int reason
+ ) {
removeNotificationInternal(
- n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */,
+ n.getKey(),
+ null,
+ stats.notificationVisibility,
+ false /* forceRemove */,
+ stats,
reason);
}
@@ -337,7 +332,11 @@
*/
private void handleInflationException(StatusBarNotification n, Exception e) {
removeNotificationInternal(
- n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */,
+ n.getKey(),
+ null,
+ null,
+ true /* forceRemove */,
+ null /* dismissedByUserStats */,
REASON_ERROR);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onInflationError(n, e);
@@ -435,19 +434,28 @@
reapplyFilterAndSort("addVisibleNotification");
}
-
- public void removeNotification(String key, RankingMap ranking,
- int reason) {
- removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
- false /* removedByUser */, reason);
+ @VisibleForTesting
+ protected void removeNotification(String key, RankingMap ranking, int reason) {
+ removeNotificationInternal(
+ key,
+ ranking,
+ obtainVisibility(key),
+ false /* forceRemove */,
+ null /* dismissedByUserStats */,
+ reason);
}
+ /**
+ * Internally remove a notification because system server has reported the notification
+ * should be removed OR the user has manually dismissed the notification
+ * @param dismissedByUserStats non-null if the user manually dismissed the notification
+ */
private void removeNotificationInternal(
String key,
@Nullable RankingMap ranking,
@Nullable NotificationVisibility visibility,
boolean forceRemove,
- boolean removedByUser,
+ DismissedByUserStats dismissedByUserStats,
int reason) {
final NotificationEntry entry = getActiveNotificationUnfiltered(key);
@@ -512,11 +520,11 @@
handleGroupSummaryRemoved(key);
removeVisibleNotification(key);
updateNotifications("removeNotificationInternal");
- removedByUser |= entryDismissed;
+ final boolean removedByUser = dismissedByUserStats != null;
mLogger.logNotifRemoved(entry.getKey(), removedByUser);
if (removedByUser && visibility != null) {
- sendNotificationRemovalToServer(entry.getKey(), entry.getSbn(), visibility);
+ sendNotificationRemovalToServer(entry.getSbn(), dismissedByUserStats);
}
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryRemoved(entry, visibility, removedByUser, reason);
@@ -534,30 +542,18 @@
}
private void sendNotificationRemovalToServer(
- String key,
StatusBarNotification notification,
- NotificationVisibility nv) {
- final String pkg = notification.getPackageName();
- final String tag = notification.getTag();
- final int id = notification.getId();
- final int userId = notification.getUser().getIdentifier();
+ DismissedByUserStats dismissedByUserStats) {
try {
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (mHeadsUpManager.isAlerting(key)) {
- dismissalSurface = NotificationStats.DISMISSAL_PEEK;
- } else if (mStatusBarStateController.isDozing()) {
- dismissalSurface = NotificationStats.DISMISSAL_AOD;
- }
- int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
mStatusBarService.onNotificationClear(
- pkg,
- tag,
- id,
- userId,
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUser().getIdentifier(),
notification.getKey(),
- dismissalSurface,
- dismissalSentiment,
- nv);
+ dismissedByUserStats.dismissalSurface,
+ dismissedByUserStats.dismissalSentiment,
+ dismissedByUserStats.notificationVisibility);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@@ -641,11 +637,7 @@
// Construct the expanded view.
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get()
- .inflateViews(
- entry,
- () -> performRemoveNotification(notification, REASON_CANCEL),
- mInflationCallback);
+ mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
}
mPendingNotifications.put(key, entry);
@@ -675,7 +667,7 @@
final String key = notification.getKey();
abortExistingInflation(key, "updateNotification");
- NotificationEntry entry = getActiveNotificationUnfiltered(key);
+ final NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry == null) {
return;
}
@@ -701,11 +693,7 @@
}
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get()
- .inflateViews(
- entry,
- () -> performRemoveNotification(notification, REASON_CANCEL),
- mInflationCallback);
+ mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
}
updateNotifications("updateNotificationInternal");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index 81494ed..0ea6857 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator;
import java.util.ArrayList;
@@ -39,9 +38,8 @@
Collections.unmodifiableList(mChildren);
private int mUntruncatedChildCount;
- @VisibleForTesting
- public GroupEntry(String key) {
- super(key);
+ GroupEntry(String key, long creationTime) {
+ super(key, creationTime);
}
@Override
@@ -59,8 +57,7 @@
return mUnmodifiableChildren;
}
- @VisibleForTesting
- public void setSummary(@Nullable NotificationEntry summary) {
+ void setSummary(@Nullable NotificationEntry summary) {
mSummary = summary;
}
@@ -98,6 +95,6 @@
return mChildren;
}
- public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>");
+ public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>", 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index 97c1523..3a05201 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -19,6 +19,8 @@
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
+import static java.util.Objects.requireNonNull;
+
import com.android.systemui.statusbar.NotificationInteractionTracker;
import java.util.Arrays;
@@ -56,7 +58,7 @@
List<NotificationEntry> children = ge.getChildren();
for (int childIndex = 0; childIndex < children.size(); childIndex++) {
dumpEntry(children.get(childIndex),
- Integer.toString(topEntryIndex) + "." + Integer.toString(childIndex),
+ topEntryIndex + "." + childIndex,
childEntryIndent,
sb,
true,
@@ -118,7 +120,7 @@
}
if (includeRecordKeeping) {
- NotificationEntry notifEntry = entry.getRepresentativeEntry();
+ NotificationEntry notifEntry = requireNonNull(entry.getRepresentativeEntry());
StringBuilder rksb = new StringBuilder();
if (!notifEntry.mLifetimeExtenders.isEmpty()) {
@@ -165,7 +167,9 @@
.append(" ");
}
- rksb.append("interacted=").append(hasBeenInteractedWith ? "yes" : "no").append(" ");
+ if (hasBeenInteractedWith) {
+ rksb.append("interacted=yes ");
+ }
String rkString = rksb.toString();
if (!rkString.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 837374f..65f5dc4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.notification.collection;
+import android.annotation.UptimeMillisLong;
+
import androidx.annotation.Nullable;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
@@ -27,14 +29,16 @@
*/
public abstract class ListEntry {
private final String mKey;
+ private final long mCreationTime;
int mFirstAddedIteration = -1;
private final ListAttachState mPreviousAttachState = ListAttachState.create();
private final ListAttachState mAttachState = ListAttachState.create();
- ListEntry(String key) {
+ ListEntry(String key, long creationTime) {
mKey = key;
+ mCreationTime = creationTime;
}
public String getKey() {
@@ -42,6 +46,19 @@
}
/**
+ * The SystemClock.uptimeMillis() when this object was created. In general, this means the
+ * moment when NotificationManager notifies our listener about the existence of this entry.
+ *
+ * This value will not change if the notification is updated, although it will change if the
+ * notification is removed and then re-posted. It is also wholly independent from
+ * Notification#when.
+ */
+ @UptimeMillisLong
+ public long getCreationTime() {
+ return mCreationTime;
+ }
+
+ /**
* Should return the "representative entry" for this ListEntry. For NotificationEntries, its
* the entry itself. For groups, it should be the summary (but if a summary doesn't exist,
* this can return null). This method exists to interface with
@@ -79,6 +96,14 @@
}
/**
+ * True if this entry has been attached to the shade at least once in its lifetime (it may not
+ * currently be attached).
+ */
+ public boolean hasBeenAttachedBefore() {
+ return mFirstAddedIteration != -1;
+ }
+
+ /**
* Stores the current attach state into {@link #getPreviousAttachState()}} and then starts a
* fresh attach state (all entries will be null/default-initialized).
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index d081e11..aaf5c4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -16,17 +16,10 @@
package com.android.systemui.statusbar.notification.collection;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
-import android.service.notification.NotificationStats;
-
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
@@ -81,7 +74,6 @@
try {
requireBinder().inflateViews(
entry,
- getDismissCallback(entry),
wrapInflationCallback(callback));
} catch (InflationException e) {
mNotifErrorManager.setInflationError(entry, e);
@@ -93,30 +85,6 @@
entry.abortTask();
}
- private Runnable getDismissCallback(NotificationEntry entry) {
- return new Runnable() {
- @Override
- public void run() {
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- /*
- * TODO: determine dismissal surface (ie: shade / headsup / aod)
- * see {@link NotificationLogger#logNotificationClear}
- */
- mNotifCollection.dismissNotification(
- entry,
- new DismissedByUserStats(
- dismissalSurface,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true,
- NotificationLogger.getNotificationLocation(entry))
- ));
- }
- };
- }
-
private NotificationContentInflater.InflationCallback wrapInflationCallback(
InflationCallback callback) {
return new NotificationContentInflater.InflationCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
deleted file mode 100644
index 339809e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2019 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.statusbar.notification.collection
-
-import android.annotation.MainThread
-import android.view.ViewGroup
-
-import com.android.systemui.statusbar.FeatureFlags
-import com.android.systemui.statusbar.notification.VisualStabilityManager
-import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-import com.android.systemui.util.Assert
-
-import java.io.FileDescriptor
-import java.io.PrintWriter
-import java.lang.IllegalStateException
-import javax.inject.Inject
-import javax.inject.Singleton
-
-/**
- * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification
- * presenter with the minimum operations required to make the old tree match the new one
- */
-@MainThread
-@Singleton
-class NotifViewManager @Inject constructor(
- private val rowRegistry: NotifViewBarn,
- private val stabilityManager: VisualStabilityManager,
- private val featureFlags: FeatureFlags
-) {
- var currentNotifs = listOf<ListEntry>()
-
- private lateinit var listContainer: SimpleNotificationListContainer
-
- fun attach(listBuilder: ShadeListBuilder) {
- if (featureFlags.isNewNotifPipelineRenderingEnabled) {
- listBuilder.setOnRenderListListener { entries: List<ListEntry> ->
- this.onNotifTreeBuilt(entries)
- }
- }
- }
-
- fun setViewConsumer(consumer: SimpleNotificationListContainer) {
- listContainer = consumer
- }
-
- /**
- * Callback for when the tree is rebuilt
- */
- fun onNotifTreeBuilt(notifList: List<ListEntry>) {
- Assert.isMainThread()
-
- /*
- * The assumption here is that anything from the old NotificationViewHierarchyManager that
- * is responsible for filtering is done via the NotifFilter logic. This tree we get should
- * be *the stuff to display* +/- redacted stuff
- */
-
- detachRows(notifList)
- attachRows(notifList)
-
- currentNotifs = notifList
- }
-
- private fun detachRows(entries: List<ListEntry>) {
- // To properly detach rows, we are looking to remove any view in the consumer that is not
- // present in the incoming list.
- //
- // Every listItem was top-level, so it's entry's parent was ROOT_ENTRY, but now
- // there are two possibilities:
- //
- // 1. It is not present in the entry list
- // 1a. It has moved to be a child in the entry list - transfer it
- // 1b. It is gone completely - remove it
- // 2. It is present in the entry list - diff the children
- getListItems(listContainer)
- .filter {
- // Ignore things that are showing the blocking helper
- !it.isBlockingHelperShowing
- }
- .forEach { listItem ->
- val noLongerTopLevel = listItem.entry.parent != ROOT_ENTRY
- val becameChild = noLongerTopLevel && listItem.entry.parent != null
-
- val idx = entries.indexOf(listItem.entry)
-
- if (noLongerTopLevel) {
- // Summaries won't become children; remove the whole group
- if (listItem.isSummaryWithChildren) {
- listItem.removeAllChildren()
- }
-
- if (becameChild) {
- // Top-level element is becoming a child, don't generate an animation
- listContainer.setChildTransferInProgress(true)
- }
- listContainer.removeListItem(listItem)
- listContainer.setChildTransferInProgress(false)
- } else if (entries[idx] is GroupEntry) {
- // A top-level entry exists. If it's a group, diff the children
- val groupChildren = (entries[idx] as GroupEntry).children
- listItem.attachedChildren?.forEach { listChild ->
- if (!groupChildren.contains(listChild.entry)) {
- listItem.removeChildNotification(listChild)
-
- // TODO: the old code only calls this if the notif is gone from
- // NEM.getActiveNotificationUnfiltered(). Do we care?
- listContainer.notifyGroupChildRemoved(
- listChild.view, listChild.view.parent as ViewGroup)
- }
- }
- }
- }
- }
-
- /** Convenience method for getting a sequence of [NotificationListItem]s */
- private fun getListItems(container: SimpleNotificationListContainer):
- Sequence<NotificationListItem> {
- return (0 until container.getContainerChildCount()).asSequence()
- .map { container.getContainerChildAt(it) }
- .filterIsInstance<NotificationListItem>()
- }
-
- private fun attachRows(entries: List<ListEntry>) {
-
- var orderChanged = false
-
- // To attach rows we can use _this one weird trick_: if the intended view to add does not
- // have a parent, then simply add it (and its children).
- entries.forEach { entry ->
- // TODO: We should eventually map GroupEntry's themselves to views so that we don't
- // depend on representativeEntry here which may actually be null in the future
- val listItem = rowRegistry.requireView(entry.representativeEntry!!)
-
- if (listItem.view.parent == null) {
- listContainer.addListItem(listItem)
- stabilityManager.notifyViewAddition(listItem.view)
- }
-
- if (entry is GroupEntry) {
- for ((idx, childEntry) in entry.children.withIndex()) {
- val childListItem = rowRegistry.requireView(childEntry)
- // Child hasn't been added yet. add it!
- if (listItem.attachedChildren == null ||
- !listItem.attachedChildren.contains(childListItem)) {
- // TODO: old code here just Log.wtf()'d here. This might wreak havoc
- if (childListItem.view.parent != null) {
- throw IllegalStateException("trying to add a notification child that " +
- "already has a parent. class: " +
- "${childListItem.view.parent?.javaClass} " +
- "\n child: ${childListItem.view}"
- )
- }
-
- listItem.addChildNotification(childListItem, idx)
- stabilityManager.notifyViewAddition(childListItem.view)
- listContainer.notifyGroupChildAdded(childListItem.view)
- }
- }
-
- // finally after removing and adding has been performed we can apply the order
- orderChanged = orderChanged ||
- listItem.applyChildOrder(
- getChildListFromParent(entry),
- stabilityManager,
- null /*TODO: stability callback */
- )
- listItem.setUntruncatedChildCount(entry.untruncatedChildCount)
- }
- }
-
- if (orderChanged) {
- listContainer.generateChildOrderChangedEvent()
- }
- }
-
- private fun getChildListFromParent(parent: ListEntry): List<NotificationListItem> {
- if (parent is GroupEntry) {
- return parent.children.map { child -> rowRegistry.requireView(child) }
- .toList()
- }
-
- return emptyList()
- }
-
- fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
- }
-}
-
-private const val TAG = "NotifViewDataSource"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index bd65ef0..387247e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -35,7 +35,6 @@
import static java.util.Objects.requireNonNull;
-import android.annotation.CurrentTimeMillisLong;
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -96,7 +95,6 @@
private final String mKey;
private StatusBarNotification mSbn;
private Ranking mRanking;
- private long mCreationTime;
/*
* Bookkeeping members
@@ -198,11 +196,10 @@
boolean allowFgsDismissal,
long creationTime
) {
- super(requireNonNull(requireNonNull(sbn).getKey()));
+ super(requireNonNull(requireNonNull(sbn).getKey()), creationTime);
requireNonNull(ranking);
- mCreationTime = creationTime;
mKey = sbn.getKey();
setSbn(sbn);
setRanking(ranking);
@@ -255,21 +252,6 @@
}
/**
- * A timestamp of SystemClock.uptimeMillis() of when this entry was first created, regardless
- * of any changes to the data presented. It is set once on creation and will never change, and
- * allows us to know exactly how long this notification has been alive for in our listener
- * service. It is entirely unrelated to the information inside of the notification.
- *
- * This is different to Notification#when because it persists throughout updates, whereas
- * system server treats every single call to notify() as a new notification and we handle
- * updates to NotificationEntry locally.
- */
- @CurrentTimeMillisLong
- public long getCreationTime() {
- return mCreationTime;
- }
-
- /**
* Should only be called by NotificationEntryManager and friends.
* TODO: Make this package-private
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index a86ab41..d45f89c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.Assert;
import com.android.systemui.util.time.SystemClock;
@@ -321,6 +322,7 @@
mPipelineState.incrementTo(STATE_FINALIZING);
logChanges();
freeEmptyGroups();
+ cleanupPluggables();
// Step 8: Dispatch the new list, first to any listeners and then to the view layer
dispatchOnBeforeRenderList(mReadOnlyNotifList);
@@ -421,7 +423,7 @@
GroupEntry group = mGroups.get(topLevelKey);
if (group == null) {
- group = new GroupEntry(topLevelKey);
+ group = new GroupEntry(topLevelKey, mSystemClock.uptimeMillis());
group.mFirstAddedIteration = mIterationCount;
mGroups.put(topLevelKey, group);
}
@@ -673,6 +675,20 @@
}
}
+ private void cleanupPluggables() {
+ callOnCleanup(mNotifPreGroupFilters);
+ callOnCleanup(mNotifPromoters);
+ callOnCleanup(mNotifFinalizeFilters);
+ callOnCleanup(mNotifComparators);
+ callOnCleanup(mNotifSections);
+ }
+
+ private void callOnCleanup(List<? extends Pluggable<?>> pluggables) {
+ for (int i = 0; i < pluggables.size(); i++) {
+ pluggables.get(i).onCleanup();
+ }
+ }
+
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
int cmp = Integer.compare(o1.getSection(), o2.getSection());
@@ -849,7 +865,7 @@
}
};
- private static final String TAG = "NotifListBuilderImpl";
+ private static final String TAG = "ShadeListBuilder";
private static final int MIN_CHILDREN_FOR_GROUP = 2;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt
deleted file mode 100644
index 2dbe555..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt
+++ /dev/null
@@ -1,43 +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.statusbar.notification.collection
-
-import android.view.View
-import android.view.ViewGroup
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-
-/**
- * Minimal interface of what [NotifViewManager] needs from [NotificationListContainer]
- */
-interface SimpleNotificationListContainer {
- /** Called to signify that a top-level element is becoming a child in the shade */
- fun setChildTransferInProgress(b: Boolean)
- /** Used to generate a list of [NotificationListItem] */
- fun getContainerChildAt(i: Int): View
- /** Similar to above */
- fun getContainerChildCount(): Int
- /** Remove a [NotificationListItem] from the container */
- fun removeListItem(li: NotificationListItem)
- /** Add a [NotificationListItem] to the container */
- fun addListItem(li: NotificationListItem)
- /** Allows [NotifViewManager] to notify the container about a group child removal */
- fun notifyGroupChildRemoved(row: View, parent: ViewGroup)
- /** Allows [NotifViewManager] to notify the container about a group child addition */
- fun notifyGroupChildAdded(row: View)
- /** [NotifViewManager] calls this when the order of the children changes */
- fun generateChildOrderChangedEvent()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 92426e5..08462c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,10 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -27,7 +23,6 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import java.util.HashSet;
import java.util.Set;
@@ -101,7 +96,6 @@
@Override
public boolean shouldInterceptDismissal(NotificationEntry entry) {
- // TODO: b/149041810 add support for intercepting app-cancelled bubble notifications
// for experimental bubbles
if (mBubbleController.handleDismissalInterception(entry)) {
mInterceptedDismissalEntries.add(entry.getKey());
@@ -121,17 +115,21 @@
private final BubbleController.NotifCallback mNotifCallback =
new BubbleController.NotifCallback() {
@Override
- public void removeNotification(NotificationEntry entry, int reason) {
+ public void removeNotification(
+ NotificationEntry entry,
+ DismissedByUserStats dismissedByUserStats,
+ int reason
+ ) {
if (isInterceptingDismissal(entry)) {
mInterceptedDismissalEntries.remove(entry.getKey());
mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry,
- createDismissedByUserStats(entry));
+ dismissedByUserStats);
} else if (mNotifPipeline.getAllNotifs().contains(entry)) {
// Bubbles are hiding the notifications from the shade, but the bubble was
// deleted; therefore, the notification should be cancelled as if it were a user
// dismissal (this won't re-enter handleInterceptDimissal because Bubbles
// will have already marked it as no longer a bubble)
- mNotifCollection.dismissNotification(entry, createDismissedByUserStats(entry));
+ mNotifCollection.dismissNotification(entry, dismissedByUserStats);
}
}
@@ -149,16 +147,4 @@
private boolean isInterceptingDismissal(NotificationEntry entry) {
return mInterceptedDismissalEntries.contains(entry.getKey());
}
-
- private DismissedByUserStats createDismissedByUserStats(NotificationEntry entry) {
- return new DismissedByUserStats(
- DISMISSAL_OTHER,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true, // was visible as a bubble
- NotificationLogger.getNotificationLocation(entry))
- );
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index b773856..95ba759 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -64,6 +64,8 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final HighPriorityProvider mHighPriorityProvider;
+ private boolean mHideSilentNotificationsOnLockscreen;
+
@Inject
public KeyguardCoordinator(
Context context,
@@ -86,6 +88,8 @@
@Override
public void attach(NotifPipeline pipeline) {
+ readShowSilentNotificationSetting();
+
setupInvalidateNotifListCallbacks();
pipeline.addFinalizeFilter(mNotifFilter);
}
@@ -147,7 +151,7 @@
return false;
}
if (NotificationUtils.useNewInterruptionModel(mContext)
- && hideSilentNotificationsOnLockscreen()) {
+ && mHideSilentNotificationsOnLockscreen) {
return mHighPriorityProvider.isHighPriority(entry);
} else {
return entry.getRepresentativeEntry() != null
@@ -155,11 +159,6 @@
}
}
- private boolean hideSilentNotificationsOnLockscreen() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0;
- }
-
private void setupInvalidateNotifListCallbacks() {
// register onKeyguardShowing callback
mKeyguardStateController.addCallback(mKeyguardCallback);
@@ -169,6 +168,11 @@
final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
@Override
public void onChange(boolean selfChange, Uri uri) {
+ if (uri.equals(Settings.Secure.getUriFor(
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
+ readShowSilentNotificationSetting();
+ }
+
if (mKeyguardStateController.isShowing()) {
invalidateListFromFilter("Settings " + uri + " changed");
}
@@ -192,6 +196,12 @@
false,
settingsObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
+ false,
+ settingsObserver,
+ UserHandle.USER_ALL);
+
// register (maybe) public mode changed callbacks:
mStatusBarStateController.addCallback(mStatusBarStateListener);
mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
@@ -208,6 +218,14 @@
mNotifFilter.invalidateList();
}
+ private void readShowSilentNotificationSetting() {
+ mHideSilentNotificationsOnLockscreen =
+ Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+ 1) == 0;
+ }
+
private final KeyguardStateController.Callback mKeyguardCallback =
new KeyguardStateController.Callback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 4159d43..ee2bb6b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -18,6 +18,8 @@
import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.IntDef;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
@@ -28,22 +30,21 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
+import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager.NotifInflationErrorListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -81,35 +82,48 @@
*/
private final int mChildBindCutoff;
+ /** How long we can delay a group while waiting for all children to inflate */
+ private final long mMaxGroupInflationDelay;
+
@Inject
public PreparationCoordinator(
PreparationCoordinatorLogger logger,
- NotifInflaterImpl notifInflater,
+ NotifInflater notifInflater,
NotifInflationErrorManager errorManager,
NotifViewBarn viewBarn,
IStatusBarService service) {
- this(logger, notifInflater, errorManager, viewBarn, service, CHILD_BIND_CUTOFF);
+ this(
+ logger,
+ notifInflater,
+ errorManager,
+ viewBarn,
+ service,
+ CHILD_BIND_CUTOFF,
+ MAX_GROUP_INFLATION_DELAY);
}
@VisibleForTesting
PreparationCoordinator(
PreparationCoordinatorLogger logger,
- NotifInflaterImpl notifInflater,
+ NotifInflater notifInflater,
NotifInflationErrorManager errorManager,
NotifViewBarn viewBarn,
IStatusBarService service,
- int childBindCutoff) {
+ int childBindCutoff,
+ long maxGroupInflationDelay) {
mLogger = logger;
mNotifInflater = notifInflater;
mNotifErrorManager = errorManager;
- mNotifErrorManager.addInflationErrorListener(mInflationErrorListener);
mViewBarn = viewBarn;
mStatusBarService = service;
mChildBindCutoff = childBindCutoff;
+ mMaxGroupInflationDelay = maxGroupInflationDelay;
}
@Override
public void attach(NotifPipeline pipeline) {
+ mNotifErrorManager.addInflationErrorListener(mInflationErrorListener);
+
pipeline.addCollectionListener(mNotifCollectionListener);
// Inflate after grouping/sorting since that affects what views to inflate.
pipeline.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
@@ -127,7 +141,6 @@
@Override
public void onEntryUpdated(NotificationEntry entry) {
abortInflation(entry, "entryUpdated");
- mInflatingNotifs.remove(entry);
@InflationState int state = getInflationState(entry);
if (state == STATE_INFLATED) {
mInflationStates.put(entry, STATE_INFLATED_INVALID);
@@ -145,7 +158,6 @@
@Override
public void onEntryCleanUp(NotificationEntry entry) {
mInflationStates.remove(entry);
- mInflatingNotifs.remove(entry);
mViewBarn.removeViewForEntry(entry);
}
};
@@ -165,17 +177,32 @@
};
private final NotifFilter mNotifInflatingFilter = new NotifFilter(TAG + "Inflating") {
+ private final Map<GroupEntry, Boolean> mIsDelayedGroupCache = new ArrayMap<>();
+
/**
- * Filters out notifications that aren't inflated
+ * Filters out notifications that either (a) aren't inflated or (b) are part of a group
+ * that isn't completely inflated yet
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- return !isInflated(entry);
+ final GroupEntry parent = requireNonNull(entry.getParent());
+ Boolean isMemberOfDelayedGroup = mIsDelayedGroupCache.get(parent);
+ if (isMemberOfDelayedGroup == null) {
+ isMemberOfDelayedGroup = shouldWaitForGroupToInflate(parent, now);
+ mIsDelayedGroupCache.put(parent, isMemberOfDelayedGroup);
+ }
+
+ return !isInflated(entry) || isMemberOfDelayedGroup;
+ }
+
+ @Override
+ public void onCleanup() {
+ mIsDelayedGroupCache.clear();
}
};
- private final NotifInflationErrorManager.NotifInflationErrorListener mInflationErrorListener =
- new NotifInflationErrorManager.NotifInflationErrorListener() {
+ private final NotifInflationErrorListener mInflationErrorListener =
+ new NotifInflationErrorListener() {
@Override
public void onNotifInflationError(NotificationEntry entry, Exception e) {
mViewBarn.removeViewForEntry(entry);
@@ -191,8 +218,9 @@
sbn.getUid(),
sbn.getInitialPid(),
e.getMessage(),
- sbn.getUserId());
+ sbn.getUser().getIdentifier());
} catch (RemoteException ex) {
+ // System server is dead, nothing to do about that
}
mNotifInflationErrorFilter.invalidateList();
}
@@ -297,11 +325,36 @@
private @InflationState int getInflationState(NotificationEntry entry) {
Integer stateObj = mInflationStates.get(entry);
- Objects.requireNonNull(stateObj,
+ requireNonNull(stateObj,
"Asking state of a notification preparation coordinator doesn't know about");
return stateObj;
}
+ private boolean shouldWaitForGroupToInflate(GroupEntry group, long now) {
+ if (group == GroupEntry.ROOT_ENTRY || group.hasBeenAttachedBefore()) {
+ return false;
+ }
+ if (isBeyondGroupInitializationWindow(group, now)) {
+ mLogger.logGroupInflationTookTooLong(group.getKey());
+ return false;
+ }
+ if (mInflatingNotifs.contains(group.getSummary())) {
+ mLogger.logDelayingGroupRelease(group.getKey(), group.getSummary().getKey());
+ return true;
+ }
+ for (NotificationEntry child : group.getChildren()) {
+ if (mInflatingNotifs.contains(child) && !child.hasBeenAttachedBefore()) {
+ mLogger.logDelayingGroupRelease(group.getKey(), child.getKey());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isBeyondGroupInitializationWindow(GroupEntry entry, long now) {
+ return now - entry.getCreationTime() > mMaxGroupInflationDelay;
+ }
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"STATE_"},
value = {STATE_UNINFLATED, STATE_INFLATED_INVALID, STATE_INFLATED, STATE_ERROR})
@@ -328,6 +381,8 @@
*/
private static final int EXTRA_VIEW_BUFFER_COUNT = 1;
+ private static final long MAX_GROUP_INFLATION_DELAY = 500;
+
private static final int CHILD_BIND_CUTOFF =
NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 75e7bc9..dd4794f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -40,6 +40,23 @@
"NOTIF INFLATION ABORTED $str1 reason=$str2"
})
}
+
+ fun logGroupInflationTookTooLong(groupKey: String) {
+ buffer.log(TAG, LogLevel.WARNING, {
+ str1 = groupKey
+ }, {
+ "Group inflation took too long far $str1, releasing children early"
+ })
+ }
+
+ fun logDelayingGroupRelease(groupKey: String, childKey: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = groupKey
+ str2 = childKey
+ }, {
+ "Delaying release of group $str1 because child $str2 is still inflating"
+ })
+ }
}
private const val TAG = "PreparationCoordinator"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index 710b137..1215ade 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -38,7 +38,6 @@
*/
void inflateViews(
NotificationEntry entry,
- Runnable onDismissRunnable,
NotificationRowContentBinder.InflationCallback callback)
throws InflationException;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 85a3bc9..8849824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -32,7 +32,6 @@
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.icon.IconManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -59,7 +58,6 @@
private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
private final NotifBindPipeline mNotifBindPipeline;
private final RowContentBindStage mRowContentBindStage;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final Provider<RowInflaterTask> mRowInflaterTaskProvider;
private final ExpandableNotificationRowComponent.Builder
mExpandableNotificationRowComponentBuilder;
@@ -79,7 +77,6 @@
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotifBindPipeline notifBindPipeline,
RowContentBindStage rowContentBindStage,
- NotificationInterruptStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
IconManager iconManager,
@@ -90,7 +87,6 @@
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
mIconManager = iconManager;
@@ -120,7 +116,6 @@
@Override
public void inflateViews(
NotificationEntry entry,
- Runnable onDismissRunnable,
NotificationRowContentBinder.InflationCallback callback)
throws InflationException {
ViewGroup parent = mListContainer.getViewParentForNotification(entry);
@@ -131,7 +126,6 @@
row.reset();
updateRow(entry, row);
inflateContentViews(entry, row, callback);
- entry.getRowController().setOnDismissRunnable(onDismissRunnable);
} else {
mIconManager.createIcons(entry);
mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
@@ -141,7 +135,6 @@
mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(row)
.notificationEntry(entry)
- .onDismissRunnable(onDismissRunnable)
.onExpandClickListener(mPresenter)
.build();
ExpandableNotificationRowController rowController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java
new file mode 100644
index 0000000..36adf9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.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 com.android.systemui.statusbar.notification.collection.inflation;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+/**
+ * Callback used when a user:
+ * 1. Manually dismisses a notification {@see ExpandableNotificationRow}.
+ * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}.
+ * {@see StatusBarNotificationActivityStarter}
+ */
+public class OnDismissCallbackImpl implements OnDismissCallback {
+ private final NotifPipeline mNotifPipeline;
+ private final NotifCollection mNotifCollection;
+ private final HeadsUpManager mHeadsUpManager;
+ private final StatusBarStateController mStatusBarStateController;
+
+ public OnDismissCallbackImpl(
+ NotifPipeline notifPipeline,
+ NotifCollection notifCollection,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController
+ ) {
+ mNotifPipeline = notifPipeline;
+ mNotifCollection = notifCollection;
+ mHeadsUpManager = headsUpManager;
+ mStatusBarStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason
+ ) {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ if (mHeadsUpManager.isAlerting(entry.getKey())) {
+ dismissalSurface = NotificationStats.DISMISSAL_PEEK;
+ } else if (mStatusBarStateController.isDozing()) {
+ dismissalSurface = NotificationStats.DISMISSAL_AOD;
+ }
+
+ mNotifCollection.dismissNotification(
+ entry,
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotifPipeline.getShadeListCount(),
+ true,
+ NotificationLogger.getNotificationLocation(entry)))
+ );
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index f150257..9782c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -25,11 +25,12 @@
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewManager;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewManagerBuilder;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import java.io.FileDescriptor;
@@ -50,9 +51,9 @@
private final NotifCoordinators mNotifPluggableCoordinators;
private final NotifInflaterImpl mNotifInflater;
private final DumpManager mDumpManager;
+ private final NotifViewManagerBuilder mNotifViewManagerBuilder;
private final FeatureFlags mFeatureFlags;
- private final NotifViewManager mNotifViewManager;
@Inject
public NotifPipelineInitializer(
@@ -63,8 +64,8 @@
NotifCoordinators notifCoordinators,
NotifInflaterImpl notifInflater,
DumpManager dumpManager,
- FeatureFlags featureFlags,
- NotifViewManager notifViewManager) {
+ NotifViewManagerBuilder notifViewManagerBuilder,
+ FeatureFlags featureFlags) {
mPipelineWrapper = pipelineWrapper;
mGroupCoalescer = groupCoalescer;
mNotifCollection = notifCollection;
@@ -73,7 +74,7 @@
mDumpManager = dumpManager;
mNotifInflater = notifInflater;
mFeatureFlags = featureFlags;
- mNotifViewManager = notifViewManager;
+ mNotifViewManagerBuilder = notifViewManagerBuilder;
}
/** Hooks the new pipeline up to NotificationManager */
@@ -93,8 +94,10 @@
mNotifPluggableCoordinators.attach(mPipelineWrapper);
// Wire up pipeline
- mNotifViewManager.setViewConsumer(listContainer);
- mNotifViewManager.attach(mListBuilder);
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ NotifViewManager notifViewManager = mNotifViewManagerBuilder.build(listContainer);
+ notifViewManager.attach(mListBuilder);
+ }
mListBuilder.attach(mNotifCollection);
mNotifCollection.attach(mGroupCoalescer);
mGroupCoalescer.attach(notificationService);
@@ -104,7 +107,6 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mNotifViewManager.dump(fd, pw, args);
mNotifPluggableCoordinators.dump(fd, pw, args);
mGroupCoalescer.dump(fd, pw, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java
new file mode 100644
index 0000000..94ffa8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.statusbar.notification.collection.legacy;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+/**
+ * Callback used when a user:
+ * 1. Manually dismisses a notification {@see ExpandableNotificationRow}.
+ * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}.
+ * {@see StatusBarNotificationActivityStarter}
+ */
+public class OnDismissCallbackImpl implements OnDismissCallback {
+ private final NotificationEntryManager mNotificationEntryManager;
+ private final HeadsUpManager mHeadsUpManager;
+ private final StatusBarStateController mStatusBarStateController;
+
+ public OnDismissCallbackImpl(
+ NotificationEntryManager notificationEntryManager,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController
+ ) {
+ mNotificationEntryManager = notificationEntryManager;
+ mHeadsUpManager = headsUpManager;
+ mStatusBarStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason
+ ) {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ if (mHeadsUpManager.isAlerting(entry.getKey())) {
+ dismissalSurface = NotificationStats.DISMISSAL_PEEK;
+ } else if (mStatusBarStateController.isDozing()) {
+ dismissalSurface = NotificationStats.DISMISSAL_AOD;
+ }
+
+ mNotificationEntryManager.performRemoveNotification(
+ entry.getSbn(),
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotificationEntryManager.getActiveNotificationsCount(),
+ true,
+ NotificationLogger.getNotificationLocation(entry))),
+ cancellationReason
+ );
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index aa10782..67f8bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -125,13 +125,18 @@
str2 = prevParent?.key
str3 = newParent?.key
}, {
- if (str2 == null && str3 != null) {
- "(Build $int1) ATTACHED {$str1}"
+
+ val action = if (str2 == null && str3 != null) {
+ "ATTACHED"
} else if (str2 != null && str3 == null) {
- "(Build $int1) DETACHED {$str1}"
+ "DETACHED"
+ } else if (str2 == null && str3 == null) {
+ "MODIFIED (DETACHED)"
} else {
- "(Build $int1) MODIFIED {$str1}"
+ "MODIFIED (ATTACHED)"
}
+
+ "(Build $int1) $action {$str1}"
})
}
@@ -146,7 +151,7 @@
} else if (str1 != null && str2 == null) {
"(Build $int1) Parent was {$str1}"
} else {
- "(Build $int1) Reparent: {$str2} -> {$str3}"
+ "(Build $int1) Reparent: {$str1} -> {$str2}"
}
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index 4270408..8e4fb75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -55,11 +55,17 @@
}
/** Set a listener to be notified when a pluggable is invalidated. */
- public void setInvalidationListener(PluggableListener<This> listener) {
+ public final void setInvalidationListener(PluggableListener<This> listener) {
mListener = listener;
}
/**
+ * Called on the pluggable once at the end of every pipeline run. Override this method to
+ * perform any necessary cleanup.
+ */
+ public void onCleanup() { }
+
+ /**
* Listener interface for when pluggables are invalidated.
*
* @param <T> The type of pluggable that is being listened to.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
index e7948cd..5400095 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
@@ -14,26 +14,22 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.collection
+package com.android.systemui.statusbar.notification.collection.render
import android.view.textclassifier.Log
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-import java.lang.IllegalStateException
-
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import javax.inject.Inject
import javax.inject.Singleton
/**
- * The ViewBarn is just a map from [ListEntry] to an instance of [NotificationListItem] which is
- * usually just an [ExpandableNotificationRow]
+ * The ViewBarn is just a map from [ListEntry] to an instance of an [ExpandableNotificationRow].
*/
@Singleton
class NotifViewBarn @Inject constructor() {
- private val DEBUG = false
+ private val rowMap = mutableMapOf<String, ExpandableNotificationRow>()
- private val rowMap = mutableMapOf<String, NotificationListItem>()
-
- fun requireView(forEntry: ListEntry): NotificationListItem {
+ fun requireView(forEntry: ListEntry): ExpandableNotificationRow {
if (DEBUG) {
Log.d(TAG, "requireView: $forEntry.key")
}
@@ -45,7 +41,7 @@
return li
}
- fun registerViewForEntry(entry: ListEntry, view: NotificationListItem) {
+ fun registerViewForEntry(entry: ListEntry, view: ExpandableNotificationRow) {
if (DEBUG) {
Log.d(TAG, "registerViewForEntry: $entry.key")
}
@@ -60,4 +56,6 @@
}
}
-private const val TAG = "NotifViewBarn"
\ No newline at end of file
+private const val TAG = "NotifViewBarn"
+
+private const val DEBUG = false
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt
new file mode 100644
index 0000000..f2e2c39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt
@@ -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.systemui.statusbar.notification.collection.render
+
+import android.annotation.MainThread
+import android.view.View
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import javax.inject.Inject
+
+/**
+ * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification
+ * presenter with the minimum operations required to make the old tree match the new one
+ */
+@MainThread
+class NotifViewManager constructor(
+ private val listContainer: NotificationListContainer,
+ private val viewBarn: NotifViewBarn,
+ private val logger: NotifViewManagerLogger
+) {
+ private val rootNode = RootWrapper(listContainer)
+ private val rows = mutableMapOf<ListEntry, RowNode>()
+
+ fun attach(listBuilder: ShadeListBuilder) {
+ listBuilder.setOnRenderListListener(::onNewNotifTree)
+ }
+
+ private fun onNewNotifTree(tree: List<ListEntry>) {
+ // Step 1: Detach all views whose parents have changed
+ detachRowsWithModifiedParents()
+
+ // Step 2: Attach all new views and reattach all views whose parents changed.
+ // Also reorder existing children to match the spec we've received
+ val orderChanged = addAndReorderChildren(rootNode, tree)
+ if (orderChanged) {
+ listContainer.generateChildOrderChangedEvent()
+ }
+ }
+
+ private fun detachRowsWithModifiedParents() {
+ val toRemove = mutableListOf<ListEntry>()
+ for (row in rows.values) {
+ val oldParentEntry = row.nodeParent?.entry
+ val newParentEntry = row.entry.parent
+
+ if (newParentEntry != oldParentEntry) {
+ // If the parent is null, then we should remove the child completely. If not, then
+ // the parent merely changed: we'll detach it for now and then attach it to the
+ // new parent in step 2.
+ val isTransfer = newParentEntry != null
+ if (!isTransfer) {
+ toRemove.add(row.entry)
+ }
+
+ if (!isTransfer && !isAttachedToRootEntry(oldParentEntry)) {
+ // If our view parent has also been removed (i.e. is no longer attached to the
+ // root entry) then we skip removing the child here
+ logger.logSkippingDetach(row.entry.key, row.nodeParent?.entry?.key)
+ } else {
+ logger.logDetachingChild(
+ row.entry.key,
+ isTransfer,
+ oldParentEntry?.key,
+ newParentEntry?.key)
+ row.nodeParent?.removeChild(row, isTransfer)
+ row.nodeParent = null
+ }
+ }
+ }
+ rows.keys.removeAll(toRemove)
+ }
+
+ private fun addAndReorderChildren(parent: ParentNode, childEntries: List<ListEntry>): Boolean {
+ var orderChanged = false
+ for ((index, entry) in childEntries.withIndex()) {
+ val row = getRowNode(entry)
+ val currView = parent.getChildViewAt(index)
+ if (currView != row.view) {
+ when (row.nodeParent) {
+ null -> {
+ logger.logAttachingChild(row.entry.key, parent.entry.key)
+ parent.addChildAt(row, index)
+ row.nodeParent = parent
+ }
+ parent -> {
+ logger.logMovingChild(row.entry.key, parent.entry.key, index)
+ parent.moveChild(row, index)
+ orderChanged = true
+ }
+ else -> {
+ throw IllegalStateException("Child ${row.entry.key} should have parent " +
+ "${parent.entry.key} but is actually " +
+ "${row.nodeParent?.entry?.key}")
+ }
+ }
+ }
+ if (row is GroupWrapper) {
+ val childOrderChanged = addAndReorderChildren(row, row.entry.children)
+ orderChanged = orderChanged || childOrderChanged
+ }
+ }
+ // TODO: setUntruncatedChildCount
+
+ return orderChanged
+ }
+
+ private fun getRowNode(entry: ListEntry): RowNode {
+ return rows.getOrPut(entry) {
+ when (entry) {
+ is NotificationEntry -> RowWrapper(entry, viewBarn.requireView(entry))
+ is GroupEntry ->
+ GroupWrapper(
+ entry,
+ viewBarn.requireView(checkNotNull(entry.summary)),
+ listContainer)
+ else -> throw RuntimeException(
+ "Unexpected entry type for ${entry.key}: ${entry.javaClass}")
+ }
+ }
+ }
+}
+
+class NotifViewManagerBuilder @Inject constructor(
+ private val viewBarn: NotifViewBarn,
+ private val logger: NotifViewManagerLogger
+) {
+ fun build(listContainer: NotificationListContainer): NotifViewManager {
+ return NotifViewManager(listContainer, viewBarn, logger)
+ }
+}
+
+private fun isAttachedToRootEntry(entry: ListEntry?): Boolean {
+ return when (entry) {
+ null -> false
+ ROOT_ENTRY -> true
+ else -> isAttachedToRootEntry(entry.parent)
+ }
+}
+
+private interface Node {
+ val entry: ListEntry
+ val nodeParent: ParentNode?
+}
+
+private interface ParentNode : Node {
+ fun getChildViewAt(index: Int): View?
+ fun addChildAt(child: RowNode, index: Int)
+ fun moveChild(child: RowNode, index: Int)
+ fun removeChild(child: RowNode, isTransfer: Boolean)
+}
+
+private interface RowNode : Node {
+ val view: ExpandableNotificationRow
+ override var nodeParent: ParentNode?
+}
+
+private class RootWrapper(
+ private val listContainer: NotificationListContainer
+) : ParentNode {
+ override val entry: ListEntry = ROOT_ENTRY
+ override val nodeParent: ParentNode? = null
+
+ override fun getChildViewAt(index: Int): View? {
+ return listContainer.getContainerChildAt(index)
+ }
+
+ override fun addChildAt(child: RowNode, index: Int) {
+ listContainer.addContainerViewAt(child.view, index)
+ }
+
+ override fun moveChild(child: RowNode, index: Int) {
+ listContainer.changeViewPosition(child.view, index)
+ }
+
+ override fun removeChild(child: RowNode, isTransfer: Boolean) {
+ if (isTransfer) {
+ listContainer.setChildTransferInProgress(true)
+ }
+ listContainer.removeContainerView(child.view)
+ if (isTransfer) {
+ listContainer.setChildTransferInProgress(false)
+ }
+ }
+}
+
+private class GroupWrapper(
+ override val entry: GroupEntry,
+ override val view: ExpandableNotificationRow,
+ val listContainer: NotificationListContainer
+) : RowNode, ParentNode {
+
+ override var nodeParent: ParentNode? = null
+
+ override fun getChildViewAt(index: Int): View? {
+ return view.getChildNotificationAt(index)
+ }
+
+ override fun addChildAt(child: RowNode, index: Int) {
+ view.addChildNotification(child.view, index)
+ listContainer.notifyGroupChildAdded(child.view)
+ }
+
+ override fun moveChild(child: RowNode, index: Int) {
+ view.removeChildNotification(child.view)
+ view.addChildNotification(child.view, index)
+ }
+
+ override fun removeChild(child: RowNode, isTransfer: Boolean) {
+ view.removeChildNotification(child.view)
+ if (isTransfer) {
+ listContainer.notifyGroupChildRemoved(child.view, view)
+ }
+ }
+}
+
+private class RowWrapper(
+ override val entry: NotificationEntry,
+ override val view: ExpandableNotificationRow
+) : RowNode {
+ override var nodeParent: ParentNode? = null
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt
new file mode 100644
index 0000000..3d56126
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.statusbar.notification.collection.render
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class NotifViewManagerLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logDetachingChild(
+ key: String,
+ isTransfer: Boolean,
+ oldParent: String?,
+ newParent: String?
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ bool1 = isTransfer
+ str2 = oldParent
+ str3 = newParent
+ }, {
+ "Detach $str1 isTransfer=$bool1 oldParent=$str2 newParent=$str3"
+ })
+ }
+
+ fun logSkippingDetach(key: String, parent: String?) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ }, {
+ "Skipping detach of $str1 because its parent $str2 is also being detached"
+ })
+ }
+
+ fun logAttachingChild(key: String, parent: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ }, {
+ "Attaching view $str1 to $str2"
+ })
+ }
+
+ fun logMovingChild(key: String, parent: String, toIndex: Int) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ int1 = toIndex
+ }, {
+ "Moving child view $str1 in $str2 to index $int1"
+ })
+ }
+}
+
+private const val TAG = "NotifViewManager"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index d661b5e..046dc3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -25,6 +25,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.qualifiers.Background;
@@ -40,9 +41,13 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.OnDismissCallbackImpl;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -56,6 +61,7 @@
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -90,8 +96,7 @@
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
ForegroundServiceDismissalFeatureController fgsFeatureController,
- HeadsUpManager headsUpManager,
- StatusBarStateController statusBarStateController) {
+ IStatusBarService statusBarService) {
return new NotificationEntryManager(
logger,
groupManager,
@@ -102,8 +107,7 @@
notificationRemoteInputManagerLazy,
leakDetector,
fgsFeatureController,
- headsUpManager,
- statusBarStateController);
+ statusBarService);
}
/** Provides an instance of {@link NotificationGutsManager} */
@@ -217,8 +221,34 @@
return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
}
+ /**
+ * Provide a dismissal callback that's triggered when a user manually dismissed a notification
+ * from the notification shade or it gets auto-cancelled by click.
+ */
+ @Provides
+ @Singleton
+ static OnDismissCallback provideOnDismissCallback(
+ FeatureFlags featureFlags,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController,
+ Lazy<NotifPipeline> pipeline,
+ Lazy<NotifCollection> notifCollection,
+ NotificationEntryManager entryManager) {
+ return featureFlags.isNewNotifPipelineRenderingEnabled()
+ ? new OnDismissCallbackImpl(
+ pipeline.get(), notifCollection.get(), headsUpManager,
+ statusBarStateController)
+ : new com.android.systemui.statusbar.notification.collection
+ .legacy.OnDismissCallbackImpl(
+ entryManager, headsUpManager, statusBarStateController);
+ }
+
/** */
@Binds
NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
+
+ /** */
+ @Binds
+ NotifInflater bindNotifInflater(NotifInflaterImpl notifInflaterImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d1ce8d1..22d0357 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -92,7 +94,6 @@
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationListItem;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -115,8 +116,7 @@
* the group summary (which contains 1 or more child notifications).
*/
public class ExpandableNotificationRow extends ActivatableNotificationView
- implements PluginListener<NotificationMenuRowPlugin>, SwipeableView,
- NotificationListItem {
+ implements PluginListener<NotificationMenuRowPlugin>, SwipeableView {
private static final boolean DEBUG = false;
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
@@ -323,7 +323,7 @@
private View mGroupParentWhenDismissed;
private boolean mShelfIconVisible;
private boolean mAboveShelf;
- private Runnable mOnDismissRunnable;
+ private OnDismissCallback mOnDismissCallback;
private boolean mIsLowPriority;
private boolean mIsColorized;
private boolean mUseIncreasedCollapsedHeight;
@@ -801,17 +801,6 @@
row.setIsChildInGroup(true, this);
}
- /**
- * Same as {@link #addChildNotification(ExpandableNotificationRow, int)}, but takes a
- * {@link NotificationListItem} instead
- *
- * @param childItem item
- * @param childIndex index
- */
- public void addChildNotification(NotificationListItem childItem, int childIndex) {
- addChildNotification((ExpandableNotificationRow) childItem.getView(), childIndex);
- }
-
public void removeChildNotification(ExpandableNotificationRow row) {
if (mChildrenContainer != null) {
mChildrenContainer.removeNotification(row);
@@ -821,9 +810,15 @@
row.setBottomRoundness(0.0f, false /* animate */);
}
- @Override
- public void removeChildNotification(NotificationListItem child) {
- removeChildNotification((ExpandableNotificationRow) child.getView());
+ /** Returns the child notification at [index], or null if no such child. */
+ @Nullable
+ public ExpandableNotificationRow getChildNotificationAt(int index) {
+ if (mChildrenContainer == null
+ || mChildrenContainer.getAttachedChildren().size() <= index) {
+ return null;
+ } else {
+ return mChildrenContainer.getAttachedChildren().get(index);
+ }
}
@Override
@@ -914,7 +909,7 @@
* @param callback the callback to invoked in case it is not allowed
* @return whether the list order has changed
*/
- public boolean applyChildOrder(List<? extends NotificationListItem> childOrder,
+ public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
VisualStabilityManager visualStabilityManager,
VisualStabilityManager.Callback callback) {
return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
@@ -1321,11 +1316,6 @@
onAttachedChildrenCountChanged();
}
- @Override
- public View getView() {
- return this;
- }
-
public void setForceUnlocked(boolean forceUnlocked) {
mForceUnlocked = forceUnlocked;
if (mIsSummaryWithChildren) {
@@ -1456,10 +1446,8 @@
}
dismiss(fromAccessibility);
if (mEntry.isClearable()) {
- // TODO: beverlyt, log dismissal
- // TODO: track dismiss sentiment
- if (mOnDismissRunnable != null) {
- mOnDismissRunnable.run();
+ if (mOnDismissCallback != null) {
+ mOnDismissCallback.onDismiss(mEntry, REASON_CANCEL);
}
}
}
@@ -1476,8 +1464,8 @@
return mIsBlockingHelperShowing && mNotificationTranslationFinished;
}
- void setOnDismissRunnable(Runnable onDismissRunnable) {
- mOnDismissRunnable = onDismissRunnable;
+ void setOnDismissCallback(OnDismissCallback onDismissCallback) {
+ mOnDismissCallback = onDismissCallback;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c983935..86a3271 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -30,7 +30,6 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.dagger.AppName;
-import com.android.systemui.statusbar.notification.row.dagger.DismissRunnable;
import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -66,7 +65,7 @@
private final ExpandableNotificationRow.CoordinateOnClickListener mOnAppOpsClickListener;
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
private final NotificationGutsManager mNotificationGutsManager;
- private Runnable mOnDismissRunnable;
+ private final OnDismissCallback mOnDismissCallback;
private final FalsingManager mFalsingManager;
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@@ -84,7 +83,7 @@
StatusBarStateController statusBarStateController,
NotificationGutsManager notificationGutsManager,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
- @DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager,
+ OnDismissCallback onDismissCallback, FalsingManager falsingManager,
PeopleNotificationIdentifier peopleNotificationIdentifier) {
mView = view;
mActivatableNotificationViewController = activatableNotificationViewController;
@@ -101,7 +100,7 @@
mOnExpandClickListener = onExpandClickListener;
mStatusBarStateController = statusBarStateController;
mNotificationGutsManager = notificationGutsManager;
- mOnDismissRunnable = onDismissRunnable;
+ mOnDismissCallback = onDismissCallback;
mOnAppOpsClickListener = mNotificationGutsManager::openGuts;
mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
mAllowLongPress = allowLongPress;
@@ -130,7 +129,7 @@
mStatusBarStateController,
mPeopleNotificationIdentifier
);
- mView.setOnDismissRunnable(mOnDismissRunnable);
+ mView.setOnDismissCallback(mOnDismissCallback);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
mView.setLongPressListener((v, x, y, item) -> {
@@ -163,10 +162,4 @@
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
-
- /** */
- public void setOnDismissRunnable(Runnable onDismissRunnable) {
- mOnDismissRunnable = onDismissRunnable;
- mView.setOnDismissRunnable(onDismissRunnable);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java
new file mode 100644
index 0000000..f1aed89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java
@@ -0,0 +1,35 @@
+/*
+ * 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.statusbar.notification.row;
+
+import android.service.notification.NotificationListenerService;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Callback when a user clicks on an auto-cancelled notification or manually swipes to dismiss the
+ * notification.
+ */
+public interface OnDismissCallback {
+
+ /**
+ * Handle a user interaction that triggers a notification dismissal.
+ */
+ void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java
deleted file mode 100644
index 4331142..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java
+++ /dev/null
@@ -1,30 +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.statusbar.notification.row.dagger;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface DismissRunnable {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
index 321656d..28ddf59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
@@ -54,8 +54,6 @@
@BindsInstance
Builder notificationEntry(NotificationEntry entry);
@BindsInstance
- Builder onDismissRunnable(@DismissRunnable Runnable runnable);
- @BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
ExpandableNotificationRowComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 907b890..93c2377 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -447,7 +447,7 @@
* @param callback
* @return whether the list order has changed
*/
- public boolean applyChildOrder(List<? extends NotificationListItem> childOrder,
+ public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
VisualStabilityManager visualStabilityManager,
VisualStabilityManager.Callback callback) {
if (childOrder == null) {
@@ -456,7 +456,7 @@
boolean result = false;
for (int i = 0; i < mAttachedChildren.size() && i < childOrder.size(); i++) {
ExpandableNotificationRow child = mAttachedChildren.get(i);
- ExpandableNotificationRow desiredChild = (ExpandableNotificationRow) childOrder.get(i);
+ ExpandableNotificationRow desiredChild = childOrder.get(i);
if (child != desiredChild) {
if (visualStabilityManager.canReorderNotification(desiredChild)) {
mAttachedChildren.remove(desiredChild);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 09ab1d8..72f3216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -18,15 +18,15 @@
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import android.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.Nullable;
+
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.SimpleNotificationListContainer;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -35,8 +35,9 @@
* Interface representing the entity that contains notifications. It can have
* notification views added and removed from it, and will manage displaying them to the user.
*/
-public interface NotificationListContainer extends ExpandableView.OnHeightChangedListener,
- VisibilityLocationProvider, SimpleNotificationListContainer {
+public interface NotificationListContainer extends
+ ExpandableView.OnHeightChangedListener,
+ VisibilityLocationProvider {
/**
* Called when a child is being transferred.
@@ -91,6 +92,7 @@
* @param i ith child to get
* @return the ith child in the list container
*/
+ @Nullable
View getContainerChildAt(int i);
/**
@@ -108,6 +110,11 @@
void addContainerView(View v);
/**
+ * Add a view to the container at a particular index
+ */
+ void addContainerViewAt(View v, int index);
+
+ /**
* Sets the maximum number of notifications to display.
*
* @param maxNotifications max number of notifications to display
@@ -188,13 +195,10 @@
return true;
}
- default void setWillExpand(boolean willExpand) {};
-
/**
- * Remove a list item from the container
- * @param v the item to remove
+ * Tells the container that an animation is about to expand it.
*/
- void removeListItem(@NonNull NotificationListItem v);
+ default void setWillExpand(boolean willExpand) {}
void setNotificationActivityStarter(NotificationActivityStarter notificationActivityStarter);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java
deleted file mode 100644
index c2dd229..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java
+++ /dev/null
@@ -1,69 +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.statusbar.notification.stack;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.view.View;
-
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import java.util.List;
-
-/**
-* A NotificationListItem is a child view of the notification list that can yield a
-* NotificationEntry when asked. I.e., it's an ExpandableNotificationRow but doesn't require us
-* to strictly rely on ExpandableNotificationRow as our consumed type
- */
-public interface NotificationListItem {
- /** @return entry for this item */
- @NonNull
- NotificationEntry getEntry();
-
- /** @return true if the blocking helper is showing */
- boolean isBlockingHelperShowing();
-
- /** @return true if this list item is a summary with children */
- boolean isSummaryWithChildren();
-
- // This generic is kind of ugly - we should change this once the old VHM is gone
- /** @return list of the children of this item */
- List<? extends NotificationListItem> getAttachedChildren();
-
- /** remove all children from this list item */
- void removeAllChildren();
-
- /** remove particular child */
- void removeChildNotification(NotificationListItem child);
-
- /** add an item as a child */
- void addChildNotification(NotificationListItem child, int childIndex);
-
- /** set the child count view should display */
- void setUntruncatedChildCount(int count);
-
- /** Update the order of the children with the new list */
- boolean applyChildOrder(
- List<? extends NotificationListItem> childOrderList,
- VisualStabilityManager vsm,
- @Nullable VisualStabilityManager.Callback callback);
-
- /** return the associated view for this list item */
- @NonNull
- View getView();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index b9d31a9..66a541a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.systemui.statusbar.notification.stack;
@@ -3387,21 +3387,11 @@
}
@Override
- public void notifyGroupChildRemoved(View child, ViewGroup parent) {
- notifyGroupChildRemoved((ExpandableView) child, parent);
- }
-
- @Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildAdded(ExpandableView row) {
onViewAddedInternal(row);
}
- @Override
- public void notifyGroupChildAdded(View view) {
- notifyGroupChildAdded((ExpandableView) view);
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
@@ -5246,20 +5236,15 @@
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void removeListItem(NotificationListItem v) {
- removeContainerView(v.getView());
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
Assert.isMainThread();
addView(v);
}
@Override
- public void addListItem(NotificationListItem v) {
- addContainerView(v.getView());
+ public void addContainerViewAt(View v, int index) {
+ Assert.isMainThread();
+ addView(v, index);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -6596,40 +6581,25 @@
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
- final List<DismissedByUserStats> dismissalUserStats = new ArrayList<>();
final int numVisibleEntries = mNotifPipeline.getShadeListCount();
for (int i = 0; i < viewsToRemove.size(); i++) {
final NotificationEntry entry = viewsToRemove.get(i).getEntry();
- final DismissedByUserStats stats =
- new DismissedByUserStats(
- DISMISSAL_SHADE,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(
- entry.getKey(),
- entry.getRanking().getRank(),
- numVisibleEntries,
- true,
- NotificationLogger.getNotificationLocation(entry)));
entriesWithRowsDismissedFromShade.add(
- new Pair<NotificationEntry, DismissedByUserStats>(entry, stats));
+ new Pair<NotificationEntry, DismissedByUserStats>(
+ entry,
+ getDismissedByUserStats(entry, numVisibleEntries)));
}
mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade);
}
} else {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
- if (selectedRows == ROWS_ALL) {
- // TODO: This is a listener method; we shouldn't be calling it. Can we just
- // call performRemoveNotification as below?
- mEntryManager.removeNotification(
- rowToRemove.getEntry().getKey(),
- null /* ranking */,
- NotificationListenerService.REASON_CANCEL_ALL);
- } else {
- mEntryManager.performRemoveNotification(
- rowToRemove.getEntry().getSbn(),
- NotificationListenerService.REASON_CANCEL_ALL);
- }
+ mEntryManager.performRemoveNotification(
+ rowToRemove.getEntry().getSbn(),
+ getDismissedByUserStats(
+ rowToRemove.getEntry(),
+ mEntryManager.getActiveNotificationsCount()),
+ NotificationListenerService.REASON_CANCEL_ALL);
} else {
rowToRemove.resetTranslation();
}
@@ -6643,6 +6613,21 @@
}
}
+ private DismissedByUserStats getDismissedByUserStats(
+ NotificationEntry entry,
+ int numVisibleEntries
+ ) {
+ return new DismissedByUserStats(
+ DISMISSAL_SHADE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ numVisibleEntries,
+ true,
+ NotificationLogger.getNotificationLocation(entry)));
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 303a083..0e76c904 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -152,6 +152,7 @@
private final Context mContext;
private final int mWakeUpDelay;
private int mMode;
+ private BiometricSourceType mBiometricType;
private KeyguardViewController mKeyguardViewController;
private DozeScrimController mDozeScrimController;
private KeyguardViewMediator mKeyguardViewMediator;
@@ -340,6 +341,7 @@
Trace.endSection();
return;
}
+ mBiometricType = biometricSourceType;
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
.setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
Optional.ofNullable(BiometricUiEvent.SUCCESS_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
@@ -615,6 +617,7 @@
private void resetMode() {
mMode = MODE_NONE;
+ mBiometricType = null;
mNotificationShadeWindowController.setForceDozeBrightness(false);
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
@@ -680,8 +683,8 @@
/**
* Successful authentication with fingerprint, face, or iris when the lockscreen fades away
*/
- public boolean isUnlockFading() {
- return mMode == MODE_UNLOCK_FADING;
+ public BiometricSourceType getBiometricType() {
+ return mBiometricType;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index e05ba12..1d82e08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -241,7 +241,7 @@
/**
* Set that we are exiting the headsUp pinned mode, but some notifications might still be
- * animating out. This is used to keep the touchable regions in a sane state.
+ * animating out. This is used to keep the touchable regions in a reasonable state.
*/
void setHeadsUpGoingAway(boolean headsUpGoingAway) {
if (headsUpGoingAway != mHeadsUpGoingAway) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 74d9f54..bfe0684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -84,7 +84,9 @@
val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
!statusBarStateController.isDozing
- val shouldListen = onKeyguard || bouncerVisible
+ val userId = KeyguardUpdateMonitor.getCurrentUser()
+ val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId)
+ val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
if (shouldListen != isListening) {
isListening = shouldListen
@@ -95,4 +97,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 141bdc2..1dc0f07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -83,6 +83,7 @@
private boolean mWakeAndUnlockRunning;
private boolean mShowingLaunchAffordance;
private boolean mBouncerShowingScrimmed;
+ private boolean mFingerprintUnlock;
private int mStatusBarState = StatusBarState.SHADE;
private LockIcon mLockIcon;
@@ -377,14 +378,19 @@
/**
* We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
* icon on top of the black front scrim.
+ * We also want to halt padlock the animation when we're in face bypass mode or dismissing the
+ * keyguard with fingerprint.
* @param wakeAndUnlock are we wake and unlocking
* @param isUnlock are we currently unlocking
*/
- public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
+ public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock,
+ BiometricSourceType type) {
if (wakeAndUnlock) {
mWakeAndUnlockRunning = true;
}
- if (isUnlock && mKeyguardBypassController.getBypassEnabled() && canBlockUpdates()) {
+ mFingerprintUnlock = type == BiometricSourceType.FINGERPRINT;
+ if (isUnlock && (mFingerprintUnlock || mKeyguardBypassController.getBypassEnabled())
+ && canBlockUpdates()) {
// We don't want the icon to change while we are unlocking
mBlockUpdates = true;
}
@@ -498,10 +504,13 @@
private boolean updateIconVisibility() {
boolean onAodOrDocked = mStatusBarStateController.isDozing() && mDocked;
boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
- if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+ boolean fingerprintOrBypass = mFingerprintUnlock
+ || mKeyguardBypassController.getBypassEnabled();
+ if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
if ((mHeadsUpManagerPhone.isHeadsUpGoingAway()
|| mHeadsUpManagerPhone.hasPinnedHeadsUp()
- || mStatusBarState == StatusBarState.KEYGUARD)
+ || mStatusBarState == StatusBarState.KEYGUARD
+ || mStatusBarState == StatusBarState.SHADE)
&& !mNotificationWakeUpCoordinator.getNotificationsFullyHidden()) {
invisible = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 5266e25..62970525 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1211,6 +1211,9 @@
}
private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
+ if (mNavigationBarView == null) {
+ return;
+ }
boolean[] feedbackEnabled = new boolean[1];
int a11yFlags = getA11yButtonState(feedbackEnabled);
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 375af6b..99cb476 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -62,7 +62,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -124,6 +124,7 @@
import java.util.function.Function;
import javax.inject.Inject;
+import javax.inject.Provider;
@StatusBarComponent.StatusBarScope
public class NotificationPanelViewController extends PanelViewController {
@@ -252,6 +253,7 @@
private final ConversationNotificationManager mConversationNotificationManager;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -495,7 +497,8 @@
ConversationNotificationManager conversationNotificationManager,
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -507,6 +510,7 @@
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -579,9 +583,11 @@
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
- KeyguardClockSwitch keyguardClockSwitch = mView.findViewById(R.id.keyguard_clock_container);
+ KeyguardClockSwitchController keyguardClockSwitchController =
+ mKeyguardClockSwitchControllerProvider.get();
+ keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
- keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
mNotificationStackScroller = mView.findViewById(R.id.notification_stack_scroller);
@@ -703,8 +709,10 @@
// Re-associate the clock container with the keyguard clock switch.
mBigClockContainer.removeAllViews();
- KeyguardClockSwitch keyguardClockSwitch = mView.findViewById(R.id.keyguard_clock_container);
- keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ KeyguardClockSwitchController keyguardClockSwitchController =
+ mKeyguardClockSwitchControllerProvider.get();
+ keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+ keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
// Update keyguard bottom area
index = mView.indexOfChild(mKeyguardBottomArea);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index e942d85..ac329e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -408,7 +408,7 @@
&& !mKeyguardStateController.isKeyguardFadingAway()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
- // Lets show the user that he can actually expand the panel
+ // Let's show the user that they can actually expand the panel
runPeekAnimation(
PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
} else {
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 c5571e8..eb62628 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3975,7 +3975,8 @@
updateScrimController();
mLockscreenLockIconController.onBiometricAuthModeChanged(
mBiometricUnlockController.isWakeAndUnlock(),
- mBiometricUnlockController.isBiometricUnlock());
+ mBiometricUnlockController.isBiometricUnlock(),
+ mBiometricUnlockController.getBiometricType());
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 3ae84ec..b89cb21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -79,15 +79,16 @@
public void removeIcon(String slot, int tag);
public void removeAllIconsForSlot(String slot);
- public static final String ICON_BLACKLIST = "icon_blacklist";
+ // TODO: See if we can rename this tunable name.
+ String ICON_HIDE_LIST = "icon_blacklist";
- /** Reads the default blacklist from config value unless blacklistStr is provided. */
- static ArraySet<String> getIconBlacklist(Context context, String blackListStr) {
+ /** Reads the default hide list from config value unless hideListStr is provided. */
+ static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
- String[] blacklist = blackListStr == null
+ String[] hideList = hideListStr == null
? context.getResources().getStringArray(R.array.config_statusBarIconBlackList)
- : blackListStr.split(",");
- for (String slot : blacklist) {
+ : hideListStr.split(",");
+ for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
ret.add(slot);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index d0e8067..21e1d31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -59,7 +59,7 @@
private static final String TAG = "StatusBarIconController";
private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
- private final ArraySet<String> mIconBlacklist = new ArraySet<>();
+ private final ArraySet<String> mIconHideList = new ArraySet<>();
// Points to light or dark context depending on the... context?
private Context mContext;
@@ -79,7 +79,7 @@
loadDimens();
commandQueue.addCallback(this);
- Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, ICON_HIDE_LIST);
}
@Override
@@ -89,12 +89,12 @@
for (int i = 0; i < allSlots.size(); i++) {
Slot slot = allSlots.get(i);
List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
- boolean blocked = mIconBlacklist.contains(slot.getName());
+ boolean hidden = mIconHideList.contains(slot.getName());
for (StatusBarIconHolder holder : holders) {
int tag = holder.getTag();
int viewIndex = getViewIndex(getSlotIndex(slot.getName()), holder.getTag());
- group.onIconAdded(viewIndex, slot.getName(), blocked, holder);
+ group.onIconAdded(viewIndex, slot.getName(), hidden, holder);
}
}
}
@@ -107,11 +107,11 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (!ICON_BLACKLIST.equals(key)) {
+ if (!ICON_HIDE_LIST.equals(key)) {
return;
}
- mIconBlacklist.clear();
- mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(mContext, newValue));
+ mIconHideList.clear();
+ mIconHideList.addAll(StatusBarIconController.getIconHideList(mContext, newValue));
ArrayList<Slot> currentSlots = getSlots();
ArrayMap<Slot, List<StatusBarIconHolder>> slotsToReAdd = new ArrayMap<>();
@@ -142,9 +142,9 @@
private void addSystemIcon(int index, StatusBarIconHolder holder) {
String slot = getSlotName(index);
int viewIndex = getViewIndex(index, holder.getTag());
- boolean blocked = mIconBlacklist.contains(slot);
+ boolean hidden = mIconHideList.contains(slot);
- mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
+ mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
}
@Override
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 7bcfb46..4de6484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
@@ -37,7 +36,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
-import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.EventLog;
@@ -71,11 +69,11 @@
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -128,6 +126,7 @@
private final NotificationPresenter mPresenter;
private final NotificationPanelViewController mNotificationPanel;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final OnDismissCallback mOnDismissCallback;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -162,6 +161,7 @@
FeatureFlags featureFlags,
MetricsLogger metricsLogger,
StatusBarNotificationActivityStarterLogger logger,
+ OnDismissCallback onDismissCallback,
StatusBar statusBar,
NotificationPresenter presenter,
@@ -197,6 +197,7 @@
mFeatureFlags = featureFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
+ mOnDismissCallback = onDismissCallback;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
@@ -574,13 +575,14 @@
private void removeNotification(NotificationEntry entry) {
// We have to post it to the UI thread for synchronization
mMainThreadHandler.post(() -> {
- Runnable removeRunnable = createRemoveRunnable(entry);
if (mPresenter.isCollapsing()) {
// To avoid lags we're only performing the remove
// after the shade was collapsed
- mShadeController.addPostCollapseAction(removeRunnable);
+ mShadeController.addPostCollapseAction(
+ () -> mOnDismissCallback.onDismiss(entry, REASON_CLICK)
+ );
} else {
- removeRunnable.run();
+ mOnDismissCallback.onDismiss(entry, REASON_CLICK);
}
});
}
@@ -595,43 +597,6 @@
}
}
- private Runnable createRemoveRunnable(NotificationEntry entry) {
- if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- return new Runnable() {
- @Override
- public void run() {
- // see NotificationLogger#logNotificationClear
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (mHeadsUpManager.isAlerting(entry.getKey())) {
- dismissalSurface = NotificationStats.DISMISSAL_PEEK;
- } else if (mNotificationPanel.hasPulsingNotifications()) {
- dismissalSurface = NotificationStats.DISMISSAL_AOD;
- }
-
- mNotifCollection.dismissNotification(
- entry,
- new DismissedByUserStats(
- dismissalSurface,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(
- entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true,
- NotificationLogger.getNotificationLocation(entry))
- ));
- }
- };
- } else {
- return new Runnable() {
- @Override
- public void run() {
- mEntryManager.performRemoveNotification(entry.getSbn(), REASON_CLICK);
- }
- };
- }
- }
-
/**
* Public builder for {@link StatusBarNotificationActivityStarter}.
*/
@@ -667,6 +632,7 @@
private final FeatureFlags mFeatureFlags;
private final MetricsLogger mMetricsLogger;
private final StatusBarNotificationActivityStarterLogger mLogger;
+ private final OnDismissCallback mOnDismissCallback;
private StatusBar mStatusBar;
private NotificationPresenter mNotificationPresenter;
@@ -704,7 +670,8 @@
FeatureFlags featureFlags,
MetricsLogger metricsLogger,
- StatusBarNotificationActivityStarterLogger logger) {
+ StatusBarNotificationActivityStarterLogger logger,
+ OnDismissCallback onDismissCallback) {
mContext = context;
mCommandQueue = commandQueue;
@@ -736,6 +703,7 @@
mFeatureFlags = featureFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
+ mOnDismissCallback = onDismissCallback;
}
/** Sets the status bar to use as {@link StatusBar}. */
@@ -793,6 +761,7 @@
mFeatureFlags,
mMetricsLogger,
mLogger,
+ mOnDismissCallback,
mStatusBar,
mNotificationPresenter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 690d573..7eefaf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -52,12 +52,12 @@
private final SecurityController mSecurityController;
private final Handler mHandler = Handler.getMain();
- private boolean mBlockAirplane;
- private boolean mBlockMobile;
- private boolean mBlockWifi;
- private boolean mBlockEthernet;
+ private boolean mHideAirplane;
+ private boolean mHideMobile;
+ private boolean mHideWifi;
+ private boolean mHideEthernet;
private boolean mActivityEnabled;
- private boolean mForceBlockWifi;
+ private boolean mForceHideWifi;
// Track as little state as possible, and only for padding purposes
private boolean mIsAirplaneMode = false;
@@ -80,7 +80,7 @@
mNetworkController = Dependency.get(NetworkController.class);
mSecurityController = Dependency.get(SecurityController.class);
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
}
@@ -114,21 +114,21 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (!StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
return;
}
- ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(mContext, newValue);
- boolean blockAirplane = blockList.contains(mSlotAirplane);
- boolean blockMobile = blockList.contains(mSlotMobile);
- boolean blockWifi = blockList.contains(mSlotWifi);
- boolean blockEthernet = blockList.contains(mSlotEthernet);
+ ArraySet<String> hideList = StatusBarIconController.getIconHideList(mContext, newValue);
+ boolean hideAirplane = hideList.contains(mSlotAirplane);
+ boolean hideMobile = hideList.contains(mSlotMobile);
+ boolean hideWifi = hideList.contains(mSlotWifi);
+ boolean hideEthernet = hideList.contains(mSlotEthernet);
- if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
- || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
- mBlockAirplane = blockAirplane;
- mBlockMobile = blockMobile;
- mBlockEthernet = blockEthernet;
- mBlockWifi = blockWifi || mForceBlockWifi;
+ if (hideAirplane != mHideAirplane || hideMobile != mHideMobile
+ || hideEthernet != mHideEthernet || hideWifi != mHideWifi) {
+ mHideAirplane = hideAirplane;
+ mHideMobile = hideMobile;
+ mHideEthernet = hideEthernet;
+ mHideWifi = hideWifi || mForceHideWifi;
// Re-register to get new callbacks.
mNetworkController.removeCallback(this);
mNetworkController.addCallback(this);
@@ -140,7 +140,7 @@
boolean activityIn, boolean activityOut, String description, boolean isTransient,
String statusLabel) {
- boolean visible = statusIcon.visible && !mBlockWifi;
+ boolean visible = statusIcon.visible && !mHideWifi;
boolean in = activityIn && mActivityEnabled && visible;
boolean out = activityOut && mActivityEnabled && visible;
@@ -189,7 +189,7 @@
// Visibility of the data type indicator changed
boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
- state.visible = statusIcon.visible && !mBlockMobile;
+ state.visible = statusIcon.visible && !mHideMobile;
state.strengthId = statusIcon.icon;
state.typeId = statusType;
state.contentDescription = statusIcon.contentDescription;
@@ -270,7 +270,7 @@
@Override
public void setEthernetIndicators(IconState state) {
- boolean visible = state.visible && !mBlockEthernet;
+ boolean visible = state.visible && !mHideEthernet;
int resId = state.icon;
String description = state.contentDescription;
@@ -284,7 +284,7 @@
@Override
public void setIsAirplaneMode(IconState icon) {
- mIsAirplaneMode = icon.visible && !mBlockAirplane;
+ mIsAirplaneMode = icon.visible && !mHideAirplane;
int resId = icon.icon;
String description = icon.contentDescription;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d30f01a..88a6263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -74,7 +74,7 @@
protected boolean mPowerSave;
private boolean mAodPowerSave;
protected boolean mWirelessCharging;
- private boolean mTestmode = false;
+ private boolean mTestMode = false;
@VisibleForTesting
boolean mHasReceivedBattery = false;
private Estimate mEstimate;
@@ -154,7 +154,7 @@
public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
+ if (mTestMode && !intent.getBooleanExtra("testmode", false)) return;
mHasReceivedBattery = true;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
@@ -172,29 +172,29 @@
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
} else if (action.equals(ACTION_LEVEL_TEST)) {
- mTestmode = true;
+ mTestMode = true;
mMainHandler.post(new Runnable() {
int curLevel = 0;
int incr = 1;
int saveLevel = mLevel;
boolean savePlugged = mPluggedIn;
- Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ Intent mTestIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
@Override
public void run() {
if (curLevel < 0) {
- mTestmode = false;
- dummy.putExtra("level", saveLevel);
- dummy.putExtra("plugged", savePlugged);
- dummy.putExtra("testmode", false);
+ mTestMode = false;
+ mTestIntent.putExtra("level", saveLevel);
+ mTestIntent.putExtra("plugged", savePlugged);
+ mTestIntent.putExtra("testmode", false);
} else {
- dummy.putExtra("level", curLevel);
- dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
+ mTestIntent.putExtra("level", curLevel);
+ mTestIntent.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
: 0);
- dummy.putExtra("testmode", true);
+ mTestIntent.putExtra("testmode", true);
}
- context.sendBroadcast(dummy);
+ context.sendBroadcast(mTestIntent);
- if (!mTestmode) return;
+ if (!mTestMode) return;
curLevel += incr;
if (curLevel == 100) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 9560195..120a0e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -191,7 +191,7 @@
mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter,
Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
- StatusBarIconController.ICON_BLACKLIST);
+ StatusBarIconController.ICON_HIDE_LIST);
mCommandQueue.addCallback(this);
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
@@ -305,8 +305,8 @@
if (CLOCK_SECONDS.equals(key)) {
mShowSeconds = TunerService.parseIntegerSwitch(newValue, false);
updateShowSeconds();
- } else {
- setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(getContext(), newValue)
+ } else if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ setClockVisibleByUser(!StatusBarIconController.getIconHideList(getContext(), newValue)
.contains("clock"));
updateClockVisibility();
}
@@ -404,7 +404,7 @@
mContentDescriptionFormat = new SimpleDateFormat(format);
/*
* Search for an unquoted "a" in the format string, so we can
- * add dummy characters around it to let us find it again after
+ * add marker characters around it to let us find it again after
* formatting and change its size.
*/
if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 54502e4..12d0617 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -198,7 +198,7 @@
can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
if (DEBUG && size > mSizeMin)
- // crazy aggressive redrawing here, for debugging only
+ // Very aggressive redrawing here, for debugging only
mNavigationBarView.postInvalidateDelayed(100);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index 66372c3..b71aafd 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -38,7 +38,7 @@
private final String mBattery;
private boolean mBatteryEnabled;
private boolean mHasPercentage;
- private ArraySet<String> mBlacklist;
+ private ArraySet<String> mHideList;
private boolean mHasSetValue;
public BatteryPreference(Context context, AttributeSet attrs) {
@@ -52,7 +52,7 @@
super.onAttached();
mHasPercentage = Settings.System.getInt(getContext().getContentResolver(),
SHOW_BATTERY_PERCENT, 0) != 0;
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
}
@Override
@@ -63,9 +63,9 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- mBatteryEnabled = !mBlacklist.contains(mBattery);
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ mBatteryEnabled = !mHideList.contains(mBattery);
}
if (!mHasSetValue) {
// Because of the complicated tri-state it can end up looping and setting state back to
@@ -88,12 +88,12 @@
MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
Settings.System.putInt(getContext().getContentResolver(), SHOW_BATTERY_PERCENT, v ? 1 : 0);
if (DISABLED.equals(value)) {
- mBlacklist.add(mBattery);
+ mHideList.add(mBattery);
} else {
- mBlacklist.remove(mBattery);
+ mHideList.remove(mBattery);
}
- Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", mBlacklist));
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", mHideList));
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
index f7d0c9f..c92d7bb 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -33,7 +33,7 @@
private final String mClock;
private boolean mClockEnabled;
private boolean mHasSeconds;
- private ArraySet<String> mBlacklist;
+ private ArraySet<String> mHideList;
private boolean mHasSetValue;
private boolean mReceivedSeconds;
private boolean mReceivedClock;
@@ -47,7 +47,7 @@
@Override
public void onAttached() {
super.onAttached();
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST,
Clock.CLOCK_SECONDS);
}
@@ -59,10 +59,10 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
mReceivedClock = true;
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- mClockEnabled = !mBlacklist.contains(mClock);
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ mClockEnabled = !mHideList.contains(mClock);
} else if (Clock.CLOCK_SECONDS.equals(key)) {
mReceivedSeconds = true;
mHasSeconds = newValue != null && Integer.parseInt(newValue) != 0;
@@ -87,12 +87,12 @@
Dependency.get(TunerService.class).setValue(Clock.CLOCK_SECONDS, SECONDS.equals(value) ? 1
: 0);
if (DISABLED.equals(value)) {
- mBlacklist.add(mClock);
+ mHideList.add(mClock);
} else {
- mBlacklist.remove(mClock);
+ mHideList.remove(mClock);
}
- Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", mBlacklist));
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", mHideList));
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index de8ccfa..cc0050b 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -34,7 +34,7 @@
public class StatusBarSwitch extends SwitchPreference implements Tunable {
- private Set<String> mBlacklist;
+ private Set<String> mHideList;
public StatusBarSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -43,7 +43,7 @@
@Override
public void onAttached() {
super.onAttached();
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
}
@Override
@@ -54,35 +54,35 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (!StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
return;
}
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- setChecked(!mBlacklist.contains(getKey()));
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ setChecked(!mHideList.contains(getKey()));
}
@Override
protected boolean persistBoolean(boolean value) {
if (!value) {
- // If not enabled add to blacklist.
- if (!mBlacklist.contains(getKey())) {
+ // If not enabled add to hideList.
+ if (!mHideList.contains(getKey())) {
MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_DISABLE,
getKey());
- mBlacklist.add(getKey());
- setList(mBlacklist);
+ mHideList.add(getKey());
+ setList(mHideList);
}
} else {
- if (mBlacklist.remove(getKey())) {
+ if (mHideList.remove(getKey())) {
MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_ENABLE, getKey());
- setList(mBlacklist);
+ setList(mHideList);
}
}
return true;
}
- private void setList(Set<String> blacklist) {
+ private void setList(Set<String> hideList) {
ContentResolver contentResolver = getContext().getContentResolver();
- Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", blacklist), ActivityManager.getCurrentUser());
+ Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", hideList), ActivityManager.getCurrentUser());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 9ad2aa2..644f758 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -60,7 +60,7 @@
// Things that use the tunable infrastructure but are now real user settings and
// shouldn't be reset with tuner settings.
- private static final String[] RESET_BLACKLIST = new String[] {
+ private static final String[] RESET_EXCEPTION_LIST = new String[] {
QSTileHost.TILES_SETTING,
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.MEDIA_CONTROLS_RESUME
@@ -116,17 +116,17 @@
private void upgradeTuner(int oldVersion, int newVersion, Handler mainHandler) {
if (oldVersion < 1) {
- String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST);
- if (blacklistStr != null) {
- ArraySet<String> iconBlacklist =
- StatusBarIconController.getIconBlacklist(mContext, blacklistStr);
+ String hideListStr = getValue(StatusBarIconController.ICON_HIDE_LIST);
+ if (hideListStr != null) {
+ ArraySet<String> iconHideList =
+ StatusBarIconController.getIconHideList(mContext, hideListStr);
- iconBlacklist.add("rotate");
- iconBlacklist.add("headset");
+ iconHideList.add("rotate");
+ iconHideList.add("headset");
Settings.Secure.putStringForUser(mContentResolver,
- StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", iconBlacklist), mCurrentUser);
+ StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", iconHideList), mCurrentUser);
}
}
if (oldVersion < 2) {
@@ -251,7 +251,7 @@
mContext.sendBroadcast(intent);
for (String key : mTunableLookup.keySet()) {
- if (ArrayUtils.contains(RESET_BLACKLIST, key)) {
+ if (ArrayUtils.contains(RESET_EXCEPTION_LIST, key)) {
continue;
}
Settings.Secure.putStringForUser(mContentResolver, key, null, user);
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index c637123..551b7b4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -23,7 +23,6 @@
import android.view.LayoutInflater;
import android.view.View;
-import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.dagger.SystemUIRootComponent;
@@ -132,11 +131,6 @@
NotificationShelf creatNotificationShelf();
/**
- * Creates the KeyguardClockSwitch.
- */
- KeyguardClockSwitch createKeyguardClockSwitch();
-
- /**
* Creates the KeyguardSliceView.
*/
KeyguardSliceView createKeyguardSliceView();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
index fbc1676..5b2c39d 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
@@ -59,9 +59,10 @@
@Singleton
@Provides
- static DisplayImeController provideDisplayImeController(
- IWindowManager wmService, DisplayController displayController,
- @Main Handler mainHandler, TransactionPool transactionPool) {
- return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ static DisplayImeController provideDisplayImeController(IWindowManager wmService,
+ DisplayController displayController, @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ return new DisplayImeController.Builder(wmService, displayController, mainHandler,
+ transactionPool).build();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
new file mode 100644
index 0000000..657e4fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.keyguard;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+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.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+
+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;
+import org.mockito.verification.VerificationMode;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
+
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ private ClockManager mClockManager;
+ @Mock
+ private KeyguardClockSwitch mView;
+ @Mock
+ private ClockPlugin mClockPlugin;
+ @Mock
+ ColorExtractor.GradientColors mGradientColors;
+
+ private KeyguardClockSwitchController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mController = new KeyguardClockSwitchController(
+ mStatusBarStateController, mColorExtractor, mClockManager);
+
+ when(mView.isAttachedToWindow()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
+ }
+
+ @Test
+ public void testAttach_viewAlreadyAttached() {
+ mController.attach(mView);
+
+ verifyAttachment(times(1));
+ }
+
+ @Test
+ public void testAttach_viewNotYetAttached() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ when(mView.isAttachedToWindow()).thenReturn(false);
+ mController.attach(mView);
+ verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
+
+ verifyAttachment(never());
+
+ listenerArgumentCaptor.getValue().onViewAttachedToWindow(mView);
+
+ verifyAttachment(times(1));
+ }
+
+
+ @Test
+ public void testAttach_viewDetached() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ mController.attach(mView);
+ verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
+
+ verifyAttachment(times(1));
+
+ listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
+
+ verify(mStatusBarStateController).removeCallback(
+ any(StatusBarStateController.StateListener.class));
+ verify(mColorExtractor).removeOnColorsChangedListener(
+ any(ColorExtractor.OnColorsChangedListener.class));
+ }
+
+ @Test
+ public void testBigClockPassesStatusBarState() {
+ ViewGroup testView = new FrameLayout(mContext);
+
+ mController.attach(mView);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
+
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.KEYGUARD);
+
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.SHADE_LOCKED);
+ }
+
+ @Test
+ public void testPluginPassesStatusBarState() {
+ ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
+
+ mController.attach(mView);
+ verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
+
+ listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);
+ verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE);
+ }
+
+ private void verifyAttachment(VerificationMode times) {
+ verify(mClockManager, times).addOnClockChangedListener(
+ any(ClockManager.ClockChangedListener.class));
+ verify(mStatusBarStateController, times).addCallback(
+ any(StatusBarStateController.StateListener.class));
+ verify(mColorExtractor, times).addOnColorsChangedListener(
+ any(ColorExtractor.OnColorsChangedListener.class));
+ verify(mView, times).updateColors(mGradientColors);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 04ceee8..4c0762e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -40,12 +40,10 @@
import android.widget.FrameLayout;
import android.widget.TextClock;
-import com.android.keyguard.clock.ClockManager;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.util.InjectionInflationController;
@@ -66,7 +64,6 @@
private FrameLayout mClockContainer;
private FrameLayout mBigClockContainer;
private TextClock mBigClock;
- private StatusBarStateController.StateListener mStateListener;
@Mock
TextClock mClockView;
@@ -108,7 +105,6 @@
mBigClock = new TextClock(getContext());
MockitoAnnotations.initMocks(this);
when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
- mStateListener = mKeyguardClockSwitch.getStateListener();
}
@Test
@@ -117,7 +113,7 @@
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
verify(mClockView).setVisibility(GONE);
assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
@@ -127,14 +123,14 @@
public void onPluginConnected_showPluginBigClock() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// THEN the big clock container is visible and it is the parent of the
// big clock view.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
@@ -144,7 +140,7 @@
@Test
public void onPluginConnected_nullView() {
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
verify(mClockView, never()).setVisibility(GONE);
}
@@ -153,11 +149,11 @@
// GIVEN a plugin has already connected
ClockPlugin plugin1 = mock(ClockPlugin.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin1);
+ mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
// WHEN a second plugin is connected
ClockPlugin plugin2 = mock(ClockPlugin.class);
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin2);
+ mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
// THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
assertThat(plugin1.getView().getParent()).isNull();
@@ -169,7 +165,7 @@
mKeyguardClockSwitch.setDarkAmount(0.5f);
// WHEN a plugin is connected
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// THEN dark amount should be initalized on the plugin.
verify(plugin).setDarkAmount(0.5f);
}
@@ -181,8 +177,8 @@
when(plugin.getView()).thenReturn(pluginView);
mClockView.setVisibility(GONE);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
verify(mClockView).setVisibility(VISIBLE);
assertThat(plugin.getView().getParent()).isNull();
@@ -193,16 +189,16 @@
// GIVEN that the big clock container is visible
FrameLayout bigClockContainer = new FrameLayout(getContext());
bigClockContainer.setVisibility(VISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(bigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(bigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getBigClockView()).thenReturn(pluginView);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected and then disconnected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN the big lock container is GONE and the big clock view doesn't have
// a parent.
assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
@@ -212,8 +208,8 @@
@Test
public void onPluginDisconnected_nullView() {
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
verify(mClockView, never()).setVisibility(GONE);
}
@@ -222,13 +218,12 @@
// GIVEN two plugins are connected
ClockPlugin plugin1 = mock(ClockPlugin.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
- ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
- listener.onClockChanged(plugin1);
+ mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
ClockPlugin plugin2 = mock(ClockPlugin.class);
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
- listener.onClockChanged(plugin2);
+ mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
// WHEN the second plugin is disconnected
- listener.onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN the default clock should be shown.
verify(mClockView).setVisibility(VISIBLE);
assertThat(plugin1.getView().getParent()).isNull();
@@ -240,10 +235,9 @@
// GIVEN a plugin is connected
ClockPlugin clockPlugin = mock(ClockPlugin.class);
when(clockPlugin.getView()).thenReturn(new TextClock(getContext()));
- ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
- listener.onClockChanged(clockPlugin);
+ mKeyguardClockSwitch.setClockPlugin(clockPlugin, StatusBarState.KEYGUARD);
// WHEN the plugin is disconnected
- listener.onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN onDestroyView is called on the plugin
verify(clockPlugin).onDestroyView();
}
@@ -260,7 +254,7 @@
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setTextColor(Color.WHITE);
@@ -284,7 +278,7 @@
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
Style style = mock(Style.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setStyle(style);
@@ -295,9 +289,9 @@
public void onStateChanged_GoneInShade() {
// GIVEN that the big clock container is visible
mBigClockContainer.setVisibility(View.VISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// WHEN transitioned to SHADE state
- mStateListener.onStateChanged(StatusBarState.SHADE);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.SHADE);
// THEN the container is gone.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
}
@@ -306,13 +300,13 @@
public void onStateChanged_VisibleInKeyguard() {
// GIVEN that the big clock container is gone
mBigClockContainer.setVisibility(View.GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN transitioned to KEYGUARD state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// THEN the container is visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -324,11 +318,11 @@
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// THEN the container remains visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -340,11 +334,11 @@
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// THEN the container is made visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -353,14 +347,14 @@
public void setKeyguardHidingBigClock_gone() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN the container set hiding clock as true
mKeyguardClockSwitch.setKeyguardHidingBigClock(true);
// THEN the container is gone.
@@ -371,14 +365,14 @@
public void setKeyguardHidingBigClock_visible() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN the container set hiding clock as false
mKeyguardClockSwitch.setKeyguardHidingBigClock(false);
// THEN the container is made visible.
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 4a8ada0..a0e5f73 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -777,7 +777,7 @@
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
- ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
+ ? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
if (data != null) intent.putExtras(data);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subscription);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 71f3d5b..ee151c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -61,6 +62,7 @@
@Mock
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -111,6 +113,15 @@
}
@Test
+ public void onConfigurationChanged_setImageResource() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+
+ verify(mMockImageView, times(2)).setImageResource(
+ getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+ }
+
+ @Test
public void performClick_fullscreenMode_removeViewAndChangeSettingsValue() {
ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(
View.OnClickListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
index 6948279..9fa5b87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
@@ -16,10 +16,10 @@
package com.android.systemui.accessibility;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import android.content.pm.ActivityInfo;
+import android.hardware.display.DisplayManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.Display;
@@ -39,8 +39,7 @@
/** Tests the ModeSwitchesController. */
public class ModeSwitchesControllerTest extends SysuiTestCase {
- @Mock
- private ModeSwitchesController.SwitchSupplier mSupplier;
+ private FakeSwitchSupplier mSupplier;
@Mock
private MagnificationModeSwitch mModeSwitch;
private ModeSwitchesController mModeSwitchesController;
@@ -49,7 +48,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mSupplier.get(anyInt())).thenReturn(mModeSwitch);
+ mSupplier = new FakeSwitchSupplier(mContext.getSystemService(DisplayManager.class));
mModeSwitchesController = new ModeSwitchesController(mSupplier);
}
@@ -70,4 +69,25 @@
verify(mModeSwitch).removeButton();
}
+
+ @Test
+ public void testControllerOnConfigurationChanged_notifyShowingButton() {
+ mModeSwitchesController.showButton(Display.DEFAULT_DISPLAY,
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ mModeSwitchesController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+
+ verify(mModeSwitch).onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+ }
+
+ private class FakeSwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
+
+ FakeSwitchSupplier(DisplayManager displayManager) {
+ super(displayManager);
+ }
+
+ @Override
+ protected MagnificationModeSwitch createInstance(Display display) {
+ return mModeSwitch;
+ }
+ }
}
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 a898c3c..2007fbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -16,13 +16,19 @@
package com.android.systemui.accessibility;
+import static android.view.Choreographer.FrameCallback;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
+import android.view.SurfaceControl;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -49,6 +55,8 @@
MirrorWindowControl mMirrorWindowControl;
@Mock
WindowMagnifierCallback mWindowMagnifierCallback;
+ @Mock
+ SurfaceControl.Transaction mTransaction;
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
@@ -56,9 +64,19 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ doAnswer(invocation -> {
+ FrameCallback callback = invocation.getArgument(0);
+ callback.doFrame(0);
+ return null;
+ }).when(mSfVsyncFrameProvider).postFrameCallback(
+ any(FrameCallback.class));
+ when(mTransaction.remove(any())).thenReturn(mTransaction);
+ when(mTransaction.setGeometry(any(), any(), any(),
+ anyInt())).thenReturn(mTransaction);
+
mWindowMagnificationController = new WindowMagnificationController(getContext(),
mHandler, mSfVsyncFrameProvider,
- mMirrorWindowControl, mWindowMagnifierCallback);
+ mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
verify(mMirrorWindowControl).setWindowDelegate(
any(MirrorWindowControl.MirrorWindowDelegate.class));
}
@@ -71,7 +89,7 @@
}
@Test
- public void createWindowMagnification_showControl() {
+ public void enableWindowMagnification_showControl() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 61a2c3f..4136013 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -17,10 +17,12 @@
package com.android.systemui.accessibility;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -96,4 +98,13 @@
verify(connectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
testBounds);
}
+
+ @Test
+ public void onConfigurationChanged_updateModeSwitches() {
+ final Configuration config = new Configuration();
+ config.densityDpi = Configuration.DENSITY_DPI_ANY;
+ mWindowMagnification.onConfigurationChanged(config);
+
+ verify(mModeSwitchesController).onConfigurationChanged(anyInt());
+ }
}
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 15828b4..b758953 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -321,7 +321,7 @@
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertThat(mRow.getEntry().isBubble()).isFalse();
Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
@@ -352,7 +352,7 @@
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
assertFalse(mRow.getEntry().isBubble());
}
@@ -365,7 +365,7 @@
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED);
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
assertTrue(mRow.getEntry().isBubble());
@@ -873,7 +873,7 @@
mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- mRow.getEntry().getSbn(), REASON_CANCEL);
+ eq(mRow.getEntry().getSbn()), any(), eq(REASON_CANCEL));
assertEquals(mBubbleData.getBubbles().size(), 1);
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
}
@@ -985,11 +985,13 @@
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- childrenRows.get(0).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(0).getEntry().getSbn()), any(),
+ eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- childrenRows.get(1).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(1).getEntry().getSbn()), any(),
+ eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(groupedBubble.getEntry().getSbn()), anyInt());
+ eq(groupedBubble.getEntry().getSbn()), any(), anyInt());
// THEN the bubble child is suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
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 686a094..43bf191 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -26,6 +26,7 @@
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.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -301,7 +302,7 @@
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// We don't remove the notification since the bubble is still in overflow.
- verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), anyInt());
+ verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -325,7 +326,8 @@
// Since the notif is dismissed and not in overflow, once the bubble is removed,
// removeNotification gets called to really remove the notif
- verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
+ verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()),
+ any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -831,10 +833,11 @@
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
verify(mNotifCallback, times(1)).removeNotification(
- childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(0).getEntry()), any(), eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotifCallback, times(1)).removeNotification(
- childrenRows.get(1).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
- verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
+ eq(childrenRows.get(1).getEntry()), any(), eq(REASON_GROUP_SUMMARY_CANCELED));
+ verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()),
+ any(), anyInt());
// THEN the bubble child still exists as a bubble and is suppressed from the shade
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 7155460..7d8728e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -94,11 +94,11 @@
@Test
fun seekBarProgress() {
- // WHEN seek bar progress is about half
+ // WHEN part of the track has been played
val data = SeekBarViewModel.Progress(true, true, 3000, 120000)
observer.onChanged(data)
- // THEN seek bar is visible
- assertThat(seekBarView.progress).isEqualTo(100)
+ // THEN seek bar shows the progress
+ assertThat(seekBarView.progress).isEqualTo(3000)
assertThat(seekBarView.max).isEqualTo(120000)
assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
assertThat(totalTimeView.getText()).isEqualTo("02:00")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
index 583d069..73164b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
@@ -44,6 +44,7 @@
private static final int TEST_BOUNDS_HEIGHT = 1000;
OneHandedAnimationController mOneHandedAnimationController;
+ OneHandedTutorialHandler mTutorialHandler;
@Mock
private SurfaceControl mMockLeash;
@@ -52,6 +53,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mTutorialHandler = new OneHandedTutorialHandler(mContext);
mOneHandedAnimationController = new OneHandedAnimationController(
new OneHandedSurfaceTransactionHelper(mContext));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 3231b28..a989cd1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -61,6 +61,7 @@
DisplayAreaInfo mDisplayAreaInfo;
Display mDisplay;
OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator;
WindowContainerToken mToken;
SurfaceControl mLeash;
@@ -97,14 +98,15 @@
mMockSurfaceTransactionHelper);
when(mMockAnimator.isRunning()).thenReturn(true);
when(mMockAnimator.setDuration(anyInt())).thenReturn(mFakeAnimator);
- when(mMockAnimator.setOneHandedAnimationCallback(any())).thenReturn(mFakeAnimator);
+ when(mMockAnimator.setOneHandedAnimationCallbacks(any())).thenReturn(mFakeAnimator);
when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator);
when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH);
when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT);
mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(mContext,
mMockDisplayController,
- mMockAnimationController);
+ mMockAnimationController,
+ mTutorialHandler);
mUpdateHandler = mDisplayAreaOrganizer.getUpdateHandler();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
index 3b284b14..694f51b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
@@ -48,6 +48,7 @@
public class OneHandedGestureHandlerTest extends OneHandedTestCase {
Instrumentation mInstrumentation;
OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
OneHandedManagerImpl mOneHandedManagerImpl;
@Mock
@@ -62,13 +63,15 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mTouchHandler = Mockito.spy(new OneHandedTouchHandler());
+ mTouchHandler = new OneHandedTouchHandler();
+ mTutorialHandler = new OneHandedTutorialHandler(mContext);
mGestureHandler = Mockito.spy(new OneHandedGestureHandler(
mContext, mMockDisplayController, mMockNavigationModeController));
mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(),
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
+ mTutorialHandler,
mGestureHandler,
mMockSysUiState);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
index 55bec54..3418ebf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
@@ -57,6 +57,8 @@
@Mock
OneHandedTouchHandler mMockTouchHandler;
@Mock
+ OneHandedTutorialHandler mMockTutorialHandler;
+ @Mock
OneHandedGestureHandler mMockGestureHandler;
@Mock
SysUiState mMockSysUiState;
@@ -69,6 +71,7 @@
mMockDisplayController,
mMockDisplayAreaOrganizer,
mMockTouchHandler,
+ mMockTutorialHandler,
mMockGestureHandler,
mMockSysUiState);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
@@ -84,7 +87,7 @@
final OneHandedAnimationController animationController = new OneHandedAnimationController(
transactionHelper);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
- mContext, mMockDisplayController, animationController);
+ mContext, mMockDisplayController, animationController, mMockTutorialHandler);
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
index 3a4ba6a..fdb28d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
@@ -46,6 +46,7 @@
public class OneHandedTouchHandlerTest extends OneHandedTestCase {
Instrumentation mInstrumentation;
OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
OneHandedManagerImpl mOneHandedManagerImpl;
@Mock
@@ -68,13 +69,15 @@
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
+ mTutorialHandler,
mGestureHandler,
mMockSysUiState);
}
@Test
public void testOneHandedManager_registerForDisplayAreaOrganizer() {
- verify(mMockDisplayAreaOrganizer, times(1)).registerTransitionCallback(mTouchHandler);
+ verify(mMockDisplayAreaOrganizer, times(1))
+ .registerTransitionCallback(mTouchHandler);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
new file mode 100644
index 0000000..f4aa00e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.onehanded;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.statusbar.phone.NavigationModeController;
+import com.android.wm.shell.common.DisplayController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
+ Instrumentation mInstrumentation;
+ OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
+ OneHandedGestureHandler mGestureHandler;
+ OneHandedManagerImpl mOneHandedManagerImpl;
+ @Mock
+ DisplayController mMockDisplayController;
+ @Mock
+ NavigationModeController mMockNavigationModeController;
+ @Mock
+ OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
+ @Mock
+ SysUiState mMockSysUiState;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTouchHandler = new OneHandedTouchHandler();
+ mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext));
+ mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
+ mMockNavigationModeController);
+ mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(),
+ mMockDisplayController,
+ mMockDisplayAreaOrganizer,
+ mTouchHandler,
+ mTutorialHandler,
+ mGestureHandler,
+ mMockSysUiState);
+ }
+
+ @Test
+ public void testOneHandedManager_registerForDisplayAreaOrganizer() {
+ verify(mMockDisplayAreaOrganizer, times(1))
+ .registerTransitionCallback(mTutorialHandler);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 4fd5d05..6f46923 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -55,7 +55,6 @@
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationListItem;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -293,15 +292,9 @@
public void notifyGroupChildAdded(ExpandableView row) {}
@Override
- public void notifyGroupChildAdded(View v) {}
-
- @Override
public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) {}
@Override
- public void notifyGroupChildRemoved(View v, ViewGroup childrenContainer) {}
-
- @Override
public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {}
@Override
@@ -327,11 +320,6 @@
}
@Override
- public void removeListItem(NotificationListItem li) {
- removeContainerView(li.getView());
- }
-
- @Override
public void setNotificationActivityStarter(
NotificationActivityStarter notificationActivityStarter) {}
@@ -342,8 +330,9 @@
}
@Override
- public void addListItem(NotificationListItem li) {
- addContainerView(li.getView());
+ public void addContainerViewAt(View v, int index) {
+ mLayout.addView(v, index);
+ mRows.add(index, v);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 8a49326..d4718e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -57,11 +57,11 @@
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -75,6 +75,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -202,8 +203,7 @@
() -> mRemoteInputManager,
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
mEntryManager.setUpWithPresenter(mPresenter);
mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -294,7 +294,8 @@
assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
// WHEN the uninflated entry is removed
- mEntryManager.performRemoveNotification(mSbn, UNDEFINED_DISMISS_REASON);
+ mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
+ UNDEFINED_DISMISS_REASON);
// THEN the entry is still removed from the allNotifications list
assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
@@ -470,7 +471,8 @@
@Test
public void testPerformRemoveNotification_removedEntry() {
mEntryManager.removeNotification(mSbn.getKey(), null, 0);
- mEntryManager.performRemoveNotification(mSbn, REASON_CANCEL);
+ mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
+ REASON_CANCEL);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
new file mode 100644
index 0000000..62667bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.statusbar.notification.collection
+
+/**
+ * Modifies a NotificationEntry
+ *
+ * The [modifier] function will be passed an instance of a NotificationEntryBuilder. Any
+ * modifications made to the builder will be applied to the [entry].
+ */
+inline fun modifyEntry(
+ entry: NotificationEntry,
+ crossinline modifier: NotificationEntryBuilder.() -> Unit
+) {
+ val builder = NotificationEntryBuilder(entry)
+ modifier(builder)
+ builder.apply(entry)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java
new file mode 100644
index 0000000..2971c05
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java
@@ -0,0 +1,82 @@
+/*
+ * 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.statusbar.notification.collection;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Builder to construct instances of {@link GroupEntry} for tests.
+ */
+public class GroupEntryBuilder {
+ private String mKey = "test_group_key";
+ private long mCreationTime = 0;
+ @Nullable private GroupEntry mParent = GroupEntry.ROOT_ENTRY;
+ private NotificationEntry mSummary = null;
+ private List<NotificationEntry> mChildren = new ArrayList<>();
+
+ /** Builds a new instance of GroupEntry */
+ public GroupEntry build() {
+ GroupEntry ge = new GroupEntry(mKey, mCreationTime);
+ ge.setParent(mParent);
+
+ ge.setSummary(mSummary);
+ mSummary.setParent(ge);
+
+ for (NotificationEntry child : mChildren) {
+ ge.addChild(child);
+ child.setParent(ge);
+ }
+ return ge;
+ }
+
+ public GroupEntryBuilder setKey(String key) {
+ mKey = key;
+ return this;
+ }
+
+ public GroupEntryBuilder setCreationTime(long creationTime) {
+ mCreationTime = creationTime;
+ return this;
+ }
+
+ public GroupEntryBuilder setParent(@Nullable GroupEntry entry) {
+ mParent = entry;
+ return this;
+ }
+
+ public GroupEntryBuilder setSummary(
+ NotificationEntry summary) {
+ mSummary = summary;
+ return this;
+ }
+
+ public GroupEntryBuilder setChildren(List<NotificationEntry> children) {
+ mChildren.clear();
+ mChildren.addAll(children);
+ return this;
+ }
+
+ /** Adds a child to the existing list of children */
+ public GroupEntryBuilder addChild(NotificationEntry entry) {
+ mChildren.add(entry);
+ return this;
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java
deleted file mode 100644
index 038dd17..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java
+++ /dev/null
@@ -1,42 +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.statusbar.notification.collection;
-
-import java.util.List;
-
-/**
- * Helper class to provide methods for test classes that need {@link GroupEntry}'s for their tests.
- */
-public class GroupEntryHelper {
- /**
- * Create a group entry for testing purposes.
- * @param groupKey group key for the group and all its entries
- * @param summary summary notification for group
- * @param children group's children notifications
- */
- public static final GroupEntry createGroup(
- String groupKey,
- NotificationEntry summary,
- List<NotificationEntry> children) {
- GroupEntry groupEntry = new GroupEntry(groupKey);
- groupEntry.setSummary(summary);
- for (NotificationEntry child : children) {
- groupEntry.addChild(child);
- }
- return groupEntry;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 2b12c22..386c866c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -191,9 +191,10 @@
@Test
public void testIsHighPriority_summaryUpdated() {
// GIVEN a GroupEntry with a lowPrioritySummary and no children
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
final NotificationEntry lowPrioritySummary = createNotifEntry(false);
- setSummary(parentEntry, lowPrioritySummary);
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(lowPrioritySummary)
+ .build();
assertFalse(mHighPriorityProvider.isHighPriority(parentEntry));
// WHEN the summary changes to high priority
@@ -214,10 +215,11 @@
// GroupEntry = parentEntry, summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
// NotificationEntry = highPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(true));
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(createNotifEntry(false))
+ .addChild(createNotifEntry(false))
+ .addChild(createNotifEntry(true))
+ .build();
// THEN the GroupEntry parentEntry is high priority since it has a high priority child
assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
@@ -228,10 +230,11 @@
// GIVEN:
// GroupEntry = parentEntry, summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
final NotificationEntry lowPriorityChild = createNotifEntry(false);
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, lowPriorityChild);
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(createNotifEntry(false))
+ .addChild(lowPriorityChild)
+ .build();
// WHEN the child entry ranking changes to high priority
lowPriorityChild.setRanking(
@@ -250,14 +253,4 @@
.setImportance(highPriority ? IMPORTANCE_HIGH : IMPORTANCE_MIN)
.build();
}
-
- private void setSummary(GroupEntry parent, NotificationEntry summary) {
- parent.setSummary(summary);
- summary.setParent(parent);
- }
-
- private void addChild(GroupEntry parent, NotificationEntry child) {
- parent.addChild(child);
- child.setParent(parent);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 4a7c6c6..1523653 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -33,6 +34,8 @@
import java.util.ArrayList;
+import kotlin.Unit;
+
/**
* Combined builder for constructing a NotificationEntry and its associated StatusBarNotification
* and Ranking. Is largely a proxy for the SBN and Ranking builders, but does a little extra magic
@@ -43,8 +46,8 @@
* Only for use in tests.
*/
public class NotificationEntryBuilder {
- private final SbnBuilder mSbnBuilder = new SbnBuilder();
- private final RankingBuilder mRankingBuilder = new RankingBuilder();
+ private final SbnBuilder mSbnBuilder;
+ private final RankingBuilder mRankingBuilder;
private final FakeSystemClock mClock = new FakeSystemClock();
private StatusBarNotification mSbn = null;
@@ -55,12 +58,49 @@
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
+ public NotificationEntryBuilder() {
+ mSbnBuilder = new SbnBuilder();
+ mRankingBuilder = new RankingBuilder();
+ }
+
+ public NotificationEntryBuilder(NotificationEntry source) {
+ mSbnBuilder = new SbnBuilder(source.getSbn());
+ mRankingBuilder = new RankingBuilder(source.getRanking());
+
+ mParent = source.getParent();
+ mSection = source.getSection();
+ mCreationTime = source.getCreationTime();
+ }
+
+ /** Build a new instance of NotificationEntry */
public NotificationEntry build() {
- StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
- mRankingBuilder.setKey(sbn.getKey());
- long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis();
- final NotificationEntry entry = new NotificationEntry(
- sbn, mRankingBuilder.build(), mClock.uptimeMillis());
+ return buildOrApply(null);
+ }
+
+ /** Modifies [target] to match the contents of this builder */
+ public void apply(NotificationEntry target) {
+ buildOrApply(target);
+ }
+
+ /** Convenience method for Kotlin callbacks that are passed a builder and need to return Unit */
+ public Unit done() {
+ return Unit.INSTANCE;
+ }
+
+ private NotificationEntry buildOrApply(NotificationEntry target) {
+ final StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
+ final Ranking ranking = mRankingBuilder.setKey(sbn.getKey()).build();
+ final long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis();
+
+ final NotificationEntry entry;
+ if (target == null) {
+ entry = new NotificationEntry(sbn, ranking, creationTime);
+ } else {
+ entry = target;
+ entry.setSbn(sbn);
+ entry.setRanking(ranking);
+ // Note: we can't modify the creation time as it's immutable
+ }
/* ListEntry properties */
entry.setParent(mParent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index f54252e..917c049 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -21,9 +21,10 @@
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -41,6 +42,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -71,13 +73,12 @@
@Mock private NotifPipeline mNotifPipeline;
private NotificationEntry mEntry;
- private KeyguardCoordinator mKeyguardCoordinator;
private NotifFilter mKeyguardFilter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mKeyguardCoordinator = new KeyguardCoordinator(
+ KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
mKeyguardUpdateMonitor, mHighPriorityProvider);
@@ -87,7 +88,7 @@
.build();
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
- mKeyguardCoordinator.attach(mNotifPipeline);
+ keyguardCoordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
@@ -186,12 +187,18 @@
public void summaryExceedsThresholdToShow() {
// GIVEN the notification doesn't exceed the threshold to show on the lockscreen
// but it's part of a group (has a parent)
- final GroupEntry parent = new GroupEntry("test_group_key");
final NotificationEntry entryWithParent = new NotificationEntryBuilder()
- .setParent(parent)
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
+ final GroupEntry parent = new GroupEntryBuilder()
+ .setKey("test_group_key")
+ .setSummary(new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .build())
+ .addChild(entryWithParent)
+ .build();
+
setupUnfilteredState(entryWithParent);
entryWithParent.setRanking(new RankingBuilder()
.setKey(entryWithParent.getKey())
@@ -200,18 +207,15 @@
// WHEN its parent does exceed threshold tot show on the lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
- parent.setSummary(new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build());
// THEN don't filter out the entry
assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
// WHEN its parent doesn't exceed threshold to show on lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
- parent.setSummary(new NotificationEntryBuilder()
+ modifyEntry(parent.getSummary(), builder -> builder
.setImportance(IMPORTANCE_MIN)
- .build());
+ .done());
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index faf9da3..bec5174 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
+import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -25,6 +27,8 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static java.util.Objects.requireNonNull;
+
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -34,15 +38,16 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryHelper;
-import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import org.junit.Before;
@@ -52,19 +57,17 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class PreparationCoordinatorTest extends SysuiTestCase {
- private static final String TEST_MESSAGE = "TEST_MESSAGE";
- private static final String TEST_GROUP_KEY = "TEST_GROUP_KEY";
- private static final int TEST_CHILD_BIND_CUTOFF = 9;
-
- private PreparationCoordinator mCoordinator;
private NotifCollectionListener mCollectionListener;
private OnBeforeFinalizeFilterListener mBeforeFilterListener;
private NotifFilter mUninflatedFilter;
@@ -75,30 +78,31 @@
@Captor private ArgumentCaptor<NotifCollectionListener> mCollectionListenerCaptor;
@Captor private ArgumentCaptor<OnBeforeFinalizeFilterListener> mBeforeFilterListenerCaptor;
- @Captor private ArgumentCaptor<NotifInflaterImpl.InflationCallback> mCallbackCaptor;
+ @Captor private ArgumentCaptor<NotifInflater.InflationCallback> mCallbackCaptor;
@Mock private NotifPipeline mNotifPipeline;
@Mock private IStatusBarService mService;
- @Mock private NotifInflaterImpl mNotifInflater;
+ @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mEntry = new NotificationEntryBuilder().build();
+ mEntry = new NotificationEntryBuilder().setParent(ROOT_ENTRY).build();
mInflationError = new Exception(TEST_MESSAGE);
mErrorManager = new NotifInflationErrorManager();
- mCoordinator = new PreparationCoordinator(
+ PreparationCoordinator coordinator = new PreparationCoordinator(
mock(PreparationCoordinatorLogger.class),
mNotifInflater,
mErrorManager,
mock(NotifViewBarn.class),
mService,
- TEST_CHILD_BIND_CUTOFF);
+ TEST_CHILD_BIND_CUTOFF,
+ TEST_MAX_GROUP_DELAY);
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
- mCoordinator.attach(mNotifPipeline);
+ coordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(2)).addFinalizeFilter(filterCaptor.capture());
List<NotifFilter> filters = filterCaptor.getAllValues();
mInflationErrorFilter = filters.get(0);
@@ -127,7 +131,7 @@
eq(mEntry.getSbn().getUid()),
eq(mEntry.getSbn().getInitialPid()),
eq(mInflationError.getMessage()),
- eq(mEntry.getSbn().getUserId()));
+ eq(mEntry.getSbn().getUser().getIdentifier()));
}
@Test
@@ -199,7 +203,11 @@
.build();
children.add(child);
}
- GroupEntry groupEntry = GroupEntryHelper.createGroup(TEST_GROUP_KEY, summary, children);
+ GroupEntry groupEntry = new GroupEntryBuilder()
+ .setKey(TEST_GROUP_KEY)
+ .setSummary(summary)
+ .setChildren(children)
+ .build();
mCollectionListener.onEntryInit(summary);
for (NotificationEntry entry : children) {
@@ -222,4 +230,139 @@
}
}
}
+
+ @Test
+ public void testPartiallyInflatedGroupsAreFilteredOut() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry child0 = group.getChildren().get(0);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN one of this children finishes inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+
+ // THEN the inflated child is still filtered out
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, 401));
+ }
+
+ @Test
+ public void testPartiallyInflatedGroupsAreFilteredOutSummaryVersion() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry summary = group.getSummary();
+ final NotificationEntry child0 = group.getChildren().get(0);
+ final NotificationEntry child1 = group.getChildren().get(1);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN all of the children (but not the summary) finish inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+ mNotifInflater.getInflateCallback(child1).onInflationFinished(child1);
+
+ // THEN the entire group is still filtered out
+ assertTrue(mUninflatedFilter.shouldFilterOut(summary, 401));
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, 401));
+ assertTrue(mUninflatedFilter.shouldFilterOut(child1, 401));
+ }
+
+ @Test
+ public void testCompletedInflatedGroupsAreReleased() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry summary = group.getSummary();
+ final NotificationEntry child0 = group.getChildren().get(0);
+ final NotificationEntry child1 = group.getChildren().get(1);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN all of the children (and the summary) finish inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+ mNotifInflater.getInflateCallback(child1).onInflationFinished(child1);
+ mNotifInflater.getInflateCallback(summary).onInflationFinished(summary);
+
+ // THEN the entire group is still filtered out
+ assertFalse(mUninflatedFilter.shouldFilterOut(summary, 401));
+ assertFalse(mUninflatedFilter.shouldFilterOut(child0, 401));
+ assertFalse(mUninflatedFilter.shouldFilterOut(child1, 401));
+ }
+
+ @Test
+ public void testPartiallyInflatedGroupsAreReleasedAfterTimeout() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry child0 = group.getChildren().get(0);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN one of this children finishes inflating and enough time passes
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+
+ // THEN the inflated child is not filtered out even though the rest of the group hasn't
+ // finished inflating yet
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, TEST_MAX_GROUP_DELAY + 1));
+ }
+
+ private static class FakeNotifInflater implements NotifInflater {
+ private Map<NotificationEntry, InflationCallback> mInflateCallbacks = new HashMap<>();
+
+ @Override
+ public void inflateViews(NotificationEntry entry, InflationCallback callback) {
+ mInflateCallbacks.put(entry, callback);
+ }
+
+ @Override
+ public void rebindViews(NotificationEntry entry, InflationCallback callback) {
+ }
+
+ @Override
+ public void abortInflation(NotificationEntry entry) {
+ }
+
+ public InflationCallback getInflateCallback(NotificationEntry entry) {
+ return requireNonNull(mInflateCallbacks.get(entry));
+ }
+ }
+
+ private void fireAddEvents(List<? extends ListEntry> entries) {
+ for (ListEntry entry : entries) {
+ if (entry instanceof GroupEntry) {
+ GroupEntry ge = (GroupEntry) entry;
+ fireAddEvents(ge.getSummary());
+ fireAddEvents(ge.getChildren());
+ } else {
+ fireAddEvents((NotificationEntry) entry);
+ }
+ }
+ }
+
+ private void fireAddEvents(NotificationEntry entry) {
+ mCollectionListener.onEntryInit(entry);
+ mCollectionListener.onEntryAdded(entry);
+ }
+
+ private static final String TEST_MESSAGE = "TEST_MESSAGE";
+ private static final String TEST_GROUP_KEY = "TEST_GROUP_KEY";
+ private static final int TEST_CHILD_BIND_CUTOFF = 9;
+ private static final int TEST_MAX_GROUP_DELAY = 100;
}
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 601df2c..a90af87 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
@@ -40,6 +40,7 @@
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.test.filters.SmallTest;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -185,8 +186,7 @@
() -> mRemoteInputManager,
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager);
@@ -252,7 +252,6 @@
mLockscreenUserManager,
pipeline,
mRowContentBindStage,
- mNotificationInterruptionStateProvider,
RowInflaterTask::new,
mExpandableNotificationRowComponentBuilder,
new IconManager(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 6d411333..ddac2ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -49,13 +49,13 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -93,7 +93,6 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.leak.LeakDetector;
@@ -193,8 +192,7 @@
() -> mRemoteInputManager,
mock(LeakDetector.class),
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class));
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a927c80..64907ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -136,6 +136,8 @@
anyFloat());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
+ assertThat(mBiometricUnlockController.getBiometricType())
+ .isEqualTo(BiometricSourceType.FINGERPRINT);
}
@Test
@@ -268,6 +270,8 @@
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+ assertThat(mBiometricUnlockController.getBiometricType())
+ .isEqualTo(BiometricSourceType.FACE);
}
@Test
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 b0b66b8..c7434f6 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
@@ -51,6 +51,7 @@
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -183,6 +184,8 @@
private BiometricUnlockController mBiometricUnlockController;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock
+ private KeyguardClockSwitchController mKeyguardClockSwitchController;
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -240,7 +243,8 @@
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
- mBiometricUnlockController, mStatusBarKeyguardViewManager);
+ mBiometricUnlockController, mStatusBarKeyguardViewManager,
+ () -> mKeyguardClockSwitchController);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelf, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index acdb2c5..3306734 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -73,6 +73,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -131,6 +132,8 @@
@Mock
private Intent mContentIntentInner;
@Mock
+ private OnDismissCallback mOnDismissCallback;
+ @Mock
private NotificationActivityStarter mNotificationActivityStarter;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -207,7 +210,8 @@
mFeatureFlags,
mock(MetricsLogger.class),
- mock(StatusBarNotificationActivityStarterLogger.class))
+ mock(StatusBarNotificationActivityStarterLogger.class),
+ mOnDismissCallback)
.setStatusBar(mStatusBar)
.setNotificationPresenter(mock(NotificationPresenter.class))
.setNotificationPanelViewController(mock(NotificationPanelViewController.class))
@@ -266,8 +270,8 @@
verify(mClickNotifier).onNotificationClick(
eq(sbn.getKey()), any(NotificationVisibility.class));
- // Notification is removed due to FLAG_AUTO_CANCEL
- verify(mEntryManager).performRemoveNotification(eq(sbn), eq(REASON_CLICK));
+ // Notification calls dismiss callback to remove notification due to FLAG_AUTO_CANCEL
+ verify(mOnDismissCallback).onDismiss(mNotificationRow.getEntry(), REASON_CLICK);
}
@Test
@@ -296,7 +300,7 @@
verifyZeroInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mOnDismissCallback, never()).onDismiss(eq(mNotificationRow.getEntry()), anyInt());
}
@Test
@@ -326,7 +330,7 @@
verifyZeroInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
}
@Test
@@ -358,6 +362,6 @@
verifyNoMoreInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
}
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index a8cd63d..915c2f6 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -32,6 +32,7 @@
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
+ "net-utils-device-common",
],
libs: [
"framework-statsd.stubs.module_lib",
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index 2b2fe45..e6444f3 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -24,7 +24,7 @@
<!-- Permissions must be defined here, and not in the base manifest, as the tethering
running in the system server process does not need any permission, and having
privileged permissions added would cause crashes on startup unless they are also
- added to the privileged permissions whitelist for that package. -->
+ added to the privileged permissions allowlist for that package. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags
index 051fbd1..86b9033 100644
--- a/packages/Tethering/proguard.flags
+++ b/packages/Tethering/proguard.flags
@@ -1,5 +1,5 @@
# Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMasterSM {
+-keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
static final int CMD_*;
static final int EVENT_*;
}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 8af1797..673cbf0 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -197,15 +197,19 @@
public static final int CMD_TETHER_UNREQUESTED = BASE_IPSERVER + 2;
// notification that this interface is down
public static final int CMD_INTERFACE_DOWN = BASE_IPSERVER + 3;
- // notification from the master SM that it had trouble enabling IP Forwarding
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble enabling IP
+ // Forwarding
public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IPSERVER + 4;
- // notification from the master SM that it had trouble disabling IP Forwarding
+ // notification from the {@link Tethering.TetherMainSM} SM that it had trouble disabling IP
+ // Forwarding
public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5;
- // notification from the master SM that it had trouble starting tethering
+ // notification from the {@link Tethering.TetherMainSM} SM that it had trouble starting
+ // tethering
public static final int CMD_START_TETHERING_ERROR = BASE_IPSERVER + 6;
- // notification from the master SM that it had trouble stopping tethering
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble stopping tethering
public static final int CMD_STOP_TETHERING_ERROR = BASE_IPSERVER + 7;
- // notification from the master SM that it had trouble setting the DNS forwarders
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble setting the DNS
+ // forwarders
public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IPSERVER + 8;
// the upstream connection has changed
public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9;
@@ -423,9 +427,13 @@
getHandler().post(() -> {
// We are on the handler thread: mDhcpServerStartIndex can be read safely.
if (mStartIndex != mDhcpServerStartIndex) {
- // This start request is obsolete. When the |server| binder token goes out of
- // scope, the garbage collector will finalize it, which causes the network stack
- // process garbage collector to collect the server itself.
+ // This start request is obsolete. Explicitly stop the DHCP server to shut
+ // down its thread. When the |server| binder token goes out of scope, the
+ // garbage collector will finalize it, which causes the network stack process
+ // garbage collector to collect the server itself.
+ try {
+ server.stop(null);
+ } catch (RemoteException e) { }
return;
}
@@ -1316,7 +1324,7 @@
/**
* This state is terminal for the per interface state machine. At this
- * point, the master state machine should have removed this interface
+ * point, the tethering main state machine should have removed this interface
* specific state machine from its list of possible recipients of
* tethering requests. The state machine itself will hang around until
* the garbage collector finds it.
diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
index 1b763ce..29c0a81 100644
--- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java
+++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
@@ -19,7 +19,7 @@
* This class defines Message.what base addresses for various state machine.
*/
public class TetheringMessageBase {
- public static final int BASE_MASTER = 0;
+ public static final int BASE_MAIN_SM = 0;
public static final int BASE_IPSERVER = 100;
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 9dace70..bb7322f 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -296,16 +296,16 @@
* Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* @param config an object that encapsulates the various tethering configuration elements.
- * Note: this method is only called from TetherMaster on the handler thread.
+ * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread.
* If there are new callers from different threads, the logic should move to
- * masterHandler to avoid race conditions.
+ * @{link Tethering.TetherMainSM} handler to avoid race conditions.
*/
public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
if (DBG) mLog.i("reevaluateSimCardProvisioning");
if (!mHandler.getLooper().isCurrentThread()) {
// Except for test, this log should not appear in normal flow.
- mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
+ mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread");
}
mEntitlementCacheValue.clear();
mCurrentEntitlementResults.clear();
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 7508a65..cfc6575 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -50,7 +50,7 @@
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-import static android.net.util.TetheringMessageBase.BASE_MASTER;
+import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -159,7 +159,7 @@
private static final boolean VDBG = false;
private static final Class[] sMessageClasses = {
- Tethering.class, TetherMasterSM.class, IpServer.class
+ Tethering.class, TetherMainSM.class, IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(sMessageClasses);
@@ -216,7 +216,7 @@
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
private final Looper mLooper;
- private final StateMachine mTetherMasterSM;
+ private final StateMachine mTetherMainSM;
private final OffloadController mOffloadController;
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
// TODO: Figure out how to merge this and other downstream-tracking objects
@@ -273,10 +273,10 @@
mTetherStates = new ArrayMap<>();
mConnectedClientsTracker = new ConnectedClientsTracker();
- mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
- mTetherMasterSM.start();
+ mTetherMainSM = new TetherMainSM("TetherMain", mLooper, deps);
+ mTetherMainSM.start();
- mHandler = mTetherMasterSM.getHandler();
+ mHandler = mTetherMainSM.getHandler();
mOffloadController = mDeps.getOffloadController(mHandler, mLog,
new OffloadController.Dependencies() {
@@ -285,8 +285,8 @@
return mConfig;
}
});
- mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
- TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+ mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog,
+ TetherMainSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new LinkedHashSet<>();
IntentFilter filter = new IntentFilter();
@@ -294,8 +294,8 @@
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
- () -> mTetherMasterSM.sendMessage(
- TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
+ () -> mTetherMainSM.sendMessage(
+ TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
stopTethering(downstream);
@@ -945,7 +945,7 @@
}
if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
- mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+ mTetherMainSM.sendMessage(TetherMainSM.CMD_UPSTREAM_CHANGED);
}
private void handleUsbAction(Intent intent) {
@@ -1170,7 +1170,7 @@
private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
if (TextUtils.isEmpty(ifname)) return;
- disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+ disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0);
}
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -1381,23 +1381,23 @@
return false;
}
- class TetherMasterSM extends StateMachine {
+ class TetherMainSM extends StateMachine {
// an interface SM has requested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MASTER + 1;
+ static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MAIN_SM + 1;
// an interface SM has unrequested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_INACTIVE = BASE_MASTER + 2;
+ static final int EVENT_IFACE_SERVING_STATE_INACTIVE = BASE_MAIN_SM + 2;
// upstream connection change - do the right thing
- static final int CMD_UPSTREAM_CHANGED = BASE_MASTER + 3;
+ static final int CMD_UPSTREAM_CHANGED = BASE_MAIN_SM + 3;
// we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = BASE_MASTER + 4;
- // Events from NetworkCallbacks that we process on the master state
+ static final int CMD_RETRY_UPSTREAM = BASE_MAIN_SM + 4;
+ // Events from NetworkCallbacks that we process on the main state
// machine thread on behalf of the UpstreamNetworkMonitor.
- static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ static final int EVENT_UPSTREAM_CALLBACK = BASE_MAIN_SM + 5;
// we treated the error and want now to clear it
- static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
- static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
+ static final int CMD_CLEAR_ERROR = BASE_MAIN_SM + 6;
+ static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MAIN_SM + 7;
// Events from EntitlementManager to choose upstream again.
- static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MASTER + 8;
+ static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MAIN_SM + 8;
private final State mInitialState;
private final State mTetherModeAliveState;
@@ -1425,7 +1425,7 @@
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
- TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
+ TetherMainSM(String name, Looper looper, TetheringDependencies deps) {
super(name, looper);
mInitialState = new InitialState();
@@ -1479,7 +1479,7 @@
}
}
- protected boolean turnOnMasterTetherSettings() {
+ protected boolean turnOnMainTetherSettings() {
final TetheringConfiguration cfg = mConfig;
try {
mNetd.ipfwdEnableForwarding(TAG);
@@ -1506,11 +1506,11 @@
return false;
}
}
- mLog.log("SET master tether settings: ON");
+ mLog.log("SET main tether settings: ON");
return true;
}
- protected boolean turnOffMasterTetherSettings() {
+ protected boolean turnOffMainTetherSettings() {
try {
mNetd.tetherStop();
} catch (RemoteException | ServiceSpecificException e) {
@@ -1526,7 +1526,7 @@
return false;
}
transitionTo(mInitialState);
- mLog.log("SET master tether settings: OFF");
+ mLog.log("SET main tether settings: OFF");
return true;
}
@@ -1730,7 +1730,7 @@
// TODO: Re-evaluate possible upstreams. Currently upstream
// reevaluation is triggered via received CONNECTIVITY_ACTION
// broadcasts that result in being passed a
- // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ // TetherMainSM.CMD_UPSTREAM_CHANGED.
handleNewUpstreamNetworkState(null);
break;
default:
@@ -1745,9 +1745,9 @@
@Override
public void enter() {
- // If turning on master tether settings fails, we have already
+ // If turning on main tether settings fails, we have already
// transitioned to an error state; exit early.
- if (!turnOnMasterTetherSettings()) {
+ if (!turnOnMainTetherSettings()) {
return;
}
@@ -1819,7 +1819,7 @@
if (mNotifyList.isEmpty()) {
// This transitions us out of TetherModeAliveState,
// either to InitialState or an error state.
- turnOffMasterTetherSettings();
+ turnOffMainTetherSettings();
break;
}
@@ -2329,7 +2329,7 @@
};
}
- // TODO: Move into TetherMasterSM.
+ // TODO: Move into TetherMainSM.
private void notifyInterfaceStateChange(IpServer who, int state, int error) {
final String iface = who.interfaceName();
synchronized (mPublicSync) {
@@ -2344,27 +2344,27 @@
mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
- // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
- // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // If TetherMainSM is in ErrorState, TetherMainSM stays there.
+ // Thus we give a chance for TetherMainSM to recover to InitialState
// by sending CMD_CLEAR_ERROR
if (error == TETHER_ERROR_INTERNAL_ERROR) {
- mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ mTetherMainSM.sendMessage(TetherMainSM.CMD_CLEAR_ERROR, who);
}
int which;
switch (state) {
case IpServer.STATE_UNAVAILABLE:
case IpServer.STATE_AVAILABLE:
- which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
+ which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
break;
case IpServer.STATE_TETHERED:
case IpServer.STATE_LOCAL_ONLY:
- which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
+ which = TetherMainSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
break;
default:
Log.wtf(TAG, "Unknown interface state: " + state);
return;
}
- mTetherMasterSM.sendMessage(which, state, 0, who);
+ mTetherMainSM.sendMessage(which, state, 0, who);
sendTetherStateChangedBroadcast();
}
@@ -2384,8 +2384,8 @@
mLog.log(String.format(
"OBSERVED LinkProperties update iface=%s state=%s lp=%s",
iface, IpServer.getStateString(state), newLp));
- final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
- mTetherMasterSM.sendMessage(which, state, 0, newLp);
+ final int which = TetherMainSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
+ mTetherMainSM.sendMessage(which, state, 0, newLp);
}
private void maybeTrackNewInterfaceLocked(final String iface) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 320427c..b17065c 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -63,7 +63,7 @@
* Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
*
* The methods and data members of this class are only to be accessed and
- * modified from the tethering master state machine thread. Any other
+ * modified from the tethering main state machine thread. Any other
* access semantics would necessitate the addition of locking.
*
* TODO: Move upstream selection logic here.
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 30a9d22..3b72b5b 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -50,6 +50,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
@@ -73,6 +74,7 @@
import android.net.RouteInfo;
import android.net.TetherOffloadRuleParcel;
import android.net.TetherStatsParcel;
+import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
@@ -163,17 +165,6 @@
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
boolean usingBpfOffload) throws Exception {
- doAnswer(inv -> {
- final IDhcpServerCallbacks cb = inv.getArgument(2);
- new Thread(() -> {
- try {
- cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
- }).run();
- return null;
- }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
@@ -225,6 +216,20 @@
when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
}
+ private void setUpDhcpServer() throws Exception {
+ doAnswer(inv -> {
+ final IDhcpServerCallbacks cb = inv.getArgument(2);
+ new Thread(() -> {
+ try {
+ cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+ } catch (RemoteException e) {
+ fail(e.getMessage());
+ }
+ }).run();
+ return null;
+ }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
+ }
+
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
@@ -258,6 +263,8 @@
return mTetherConfig;
}
}));
+
+ setUpDhcpServer();
}
@Test
@@ -965,6 +972,31 @@
reset(mRaDaemon);
}
+ @Test
+ public void testStopObsoleteDhcpServer() throws Exception {
+ final ArgumentCaptor<DhcpServerCallbacks> cbCaptor =
+ ArgumentCaptor.forClass(DhcpServerCallbacks.class);
+ doNothing().when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(),
+ cbCaptor.capture());
+ initStateMachine(TETHERING_WIFI);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ verify(mDhcpServer, never()).startWithCallbacks(any(), any());
+
+ // No stop dhcp server because dhcp server is not created yet.
+ dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+ verify(mDhcpServer, never()).stop(any());
+
+ // Stop obsolete dhcp server.
+ try {
+ final DhcpServerCallbacks cb = cbCaptor.getValue();
+ cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+ mLooper.dispatchAll();
+ } catch (RemoteException e) {
+ fail(e.getMessage());
+ }
+ verify(mDhcpServer).stop(any());
+ }
+
private void assertDhcpServingParams(final DhcpServingParamsParcel params,
final IpPrefix prefix) {
// Last address byte is random
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 1b710d0..46fe5cf 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
@@ -337,11 +337,11 @@
}
public class MockTetheringDependencies extends TetheringDependencies {
- StateMachine mUpstreamNetworkMonitorMasterSM;
+ StateMachine mUpstreamNetworkMonitorSM;
ArrayList<IpServer> mIpv6CoordinatorNotifyList;
public void reset() {
- mUpstreamNetworkMonitorMasterSM = null;
+ mUpstreamNetworkMonitorSM = null;
mIpv6CoordinatorNotifyList = null;
}
@@ -368,7 +368,7 @@
@Override
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
StateMachine target, SharedLog log, int what) {
- mUpstreamNetworkMonitorMasterSM = target;
+ mUpstreamNetworkMonitorSM = target;
return mUpstreamNetworkMonitor;
}
@@ -911,8 +911,8 @@
initTetheringUpstream(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamState);
@@ -1126,7 +1126,7 @@
verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
// This never gets called because of the exception thrown above.
verify(mNetd, times(0)).tetherStartWithConfiguration(any());
- // When the master state machine transitions to an error state it tells
+ // When the main state machine transitions to an error state it tells
// downstream interfaces, which causes us to tell Wi-Fi about the error
// so it can take down AP mode.
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
@@ -1753,8 +1753,8 @@
@Test
public void testUpstreamNetworkChanged() {
- final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+ final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+ mTetheringDependencies.mUpstreamNetworkMonitorSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
@@ -1765,8 +1765,8 @@
@Test
public void testUpstreamCapabilitiesChanged() {
- final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+ final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+ mTetheringDependencies.mUpstreamNetworkMonitorSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
@@ -1891,8 +1891,8 @@
any(), any());
reset(mNetd, mUsbManager);
upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamNetwork);
@@ -1929,8 +1929,8 @@
final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState(
upstreamAddress, 16, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamNetwork);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index a08c2dd..ed2b26f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -384,7 +384,7 @@
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
- return;
+ magnifier = createWindowMagnifier(displayId);
}
if (DBG) {
Slog.i(TAG,
@@ -401,6 +401,15 @@
}
@Override
+ public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
+ if (magnifier == null) {
+ magnifier = createWindowMagnifier(displayId);
+ }
+ magnifier.onSourceBoundsChanged(sourceBounds);
+ }
+
+ @Override
public void binderDied() {
synchronized (mLock) {
Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient);
@@ -427,6 +436,8 @@
private final WindowMagnificationManager mWindowMagnificationManager;
//Records the bounds of window magnifier.
private final Rect mBounds = new Rect();
+ //The magnified bounds on the screen.
+ private final Rect mSourceBounds = new Rect();
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
@@ -502,6 +513,10 @@
void reset() {
mEnabled = false;
}
+
+ public void onSourceBoundsChanged(Rect sourceBounds) {
+ mSourceBounds.set(sourceBounds);
+ }
}
private boolean enableWindowMagnification(int displayId, float scale, float centerX,
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 103151d..7ee607c 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -219,7 +219,7 @@
if (connected) {
synchronized (mLock) {
if (mZombie) {
- // Sanity check - shouldn't happen
+ // Validation check - shouldn't happen
if (mRemoteService == null) {
Slog.w(TAG, "Cannot resurrect sessions because remote service is null");
return;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index b229e9f..3562205 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -16,11 +16,13 @@
package com.android.server.appwidget;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import com.android.server.AppWidgetBackupBridge;
-import com.android.server.FgThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
/**
* SystemService that publishes an IAppWidgetService.
@@ -49,12 +51,12 @@
}
@Override
- public void onStopUser(int userHandle) {
- mImpl.onUserStopped(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mImpl.onUserStopped(user.getUserIdentifier());
}
@Override
- public void onSwitchUser(int userHandle) {
- mImpl.reloadWidgetsMaskedStateForGroup(userHandle);
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mImpl.reloadWidgetsMaskedStateForGroup(to.getUserIdentifier());
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 089861b..663fd62 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -84,6 +84,7 @@
import com.android.internal.util.SyncResultReceiver;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.SystemService.TargetUser;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -363,7 +364,7 @@
}
@Override // from SystemService
- public void onSwitchUser(int userHandle) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
mUi.hideAll(null);
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 5a9320f..b0755ac 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -161,8 +161,9 @@
@Override
public void onFailure(int requestId, CharSequence message) {
+ String errorMessage = message == null ? "" : String.valueOf(message);
fillRequest.completeExceptionally(
- new RuntimeException(String.valueOf(message)));
+ new RuntimeException(errorMessage));
}
});
return fillRequest;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7ab4369..1970b57 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1710,7 +1710,7 @@
if ((state & ViewState.STATE_AUTOFILLED_ONCE) != 0) {
final String datasetId = viewState.getDatasetId();
if (datasetId == null) {
- // Sanity check - should never happen.
+ // Validation check - should never happen.
Slog.w(TAG, "logContextCommitted(): no dataset id on " + viewState);
continue;
}
@@ -1844,7 +1844,7 @@
final ArrayMap<String, String> algorithms = userData.getFieldClassificationAlgorithms();
final ArrayMap<String, Bundle> args = userData.getFieldClassificationArgs();
- // Sanity check
+ // Validation check
if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
final int valuesLength = userValues == null ? -1 : userValues.length;
final int idsLength = categoryIds == null ? -1 : categoryIds.length;
@@ -2668,12 +2668,12 @@
final String currentUrl = mUrlBar == null ? null
: mUrlBar.getText().toString().trim();
if (currentUrl == null) {
- // Sanity check - shouldn't happen.
+ // Validation check - shouldn't happen.
wtf(null, "URL bar value changed, but current value is null");
return;
}
if (value == null || ! value.isText()) {
- // Sanity check - shouldn't happen.
+ // Validation check - shouldn't happen.
wtf(null, "URL bar value changed to null or non-text: %s", value);
return;
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c839ce94..12e6e10 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -19,6 +19,7 @@
import static java.util.Collections.emptySet;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -60,6 +61,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.backup.utils.RandomAccessFileUtils;
import java.io.File;
@@ -1605,13 +1607,13 @@
}
@Override
- public void onUnlockUser(int userId) {
- sInstance.onUnlockUser(userId);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ sInstance.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userId) {
- sInstance.onStopUser(userId);
+ public void onUserStopping(@NonNull TargetUser user) {
+ sInstance.onStopUser(user.getUserIdentifier());
}
@VisibleForTesting
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2de26b7..3ab81cb 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2307,7 +2307,7 @@
public void enqueueFullBackup(String packageName, long lastBackedUp) {
FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
synchronized (mQueueLock) {
- // First, sanity check that we aren't adding a duplicate. Slow but
+ // First, check that we aren't adding a duplicate. Slow but
// straightforward; we'll have at most on the order of a few hundred
// items in this list.
dequeueFullBackupLocked(packageName);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index a69bd6b..0a11774 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -24,8 +24,6 @@
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
-import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -143,7 +141,7 @@
private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
OutputStream ofstream) throws Exception {
- // User key will be used to encrypt the master key.
+ // User key will be used to encrypt the encryption key.
byte[] newUserSalt = mUserBackupManagerService
.randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
SecretKey userKey = PasswordUtils
@@ -151,16 +149,16 @@
newUserSalt,
PasswordUtils.PBKDF2_HASH_ROUNDS);
- // the master key is random for each backup
- byte[] masterPw = new byte[256 / 8];
- mUserBackupManagerService.getRng().nextBytes(masterPw);
+ // the encryption key is random for each backup
+ byte[] encryptionKey = new byte[256 / 8];
+ mUserBackupManagerService.getRng().nextBytes(encryptionKey);
byte[] checksumSalt = mUserBackupManagerService
.randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
- // primary encryption of the datastream with the random key
+ // primary encryption of the datastream with the encryption key
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
- c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
+ SecretKeySpec encryptionKeySpec = new SecretKeySpec(encryptionKey, "AES");
+ c.init(Cipher.ENCRYPT_MODE, encryptionKeySpec);
OutputStream finalOutput = new CipherOutputStream(ofstream, c);
// line 4: name of encryption algorithm
@@ -169,7 +167,7 @@
// line 5: user password salt [hex]
headerbuf.append(PasswordUtils.byteArrayToHex(newUserSalt));
headerbuf.append('\n');
- // line 6: master key checksum salt [hex]
+ // line 6: encryption key checksum salt [hex]
headerbuf.append(PasswordUtils.byteArrayToHex(checksumSalt));
headerbuf.append('\n');
// line 7: number of PBKDF2 rounds used [decimal]
@@ -184,21 +182,21 @@
headerbuf.append(PasswordUtils.byteArrayToHex(IV));
headerbuf.append('\n');
- // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
+ // line 9: encryption IV + key blob, encrypted by the user key [hex]. Blob format:
// [byte] IV length = Niv
// [array of Niv bytes] IV itself
- // [byte] master key length = Nmk
- // [array of Nmk bytes] master key itself
- // [byte] MK checksum hash length = Nck
- // [array of Nck bytes] master key checksum hash
+ // [byte] encryption key length = Nek
+ // [array of Nek bytes] encryption key itself
+ // [byte] encryption key checksum hash length = Nck
+ // [array of Nck bytes] encryption key checksum hash
//
- // The checksum is the (master key + checksum salt), run through the
+ // The checksum is the (encryption key + checksum salt), run through the
// stated number of PBKDF2 rounds
IV = c.getIV();
- byte[] mk = masterKeySpec.getEncoded();
+ byte[] mk = encryptionKeySpec.getEncoded();
byte[] checksum = PasswordUtils
.makeKeyChecksum(PBKDF_CURRENT,
- masterKeySpec.getEncoded(),
+ encryptionKeySpec.getEncoded(),
checksumSalt, PasswordUtils.PBKDF2_HASH_ROUNDS);
ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
@@ -347,15 +345,15 @@
// When line 4 is not "none", then additional header data follows:
//
// line 5: user password salt [hex]
- // line 6: master key checksum salt [hex]
- // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
+ // line 6: encryption key checksum salt [hex]
+ // line 7: number of PBKDF2 rounds to use (same for user & encryption key) [decimal]
// line 8: IV of the user key [hex]
- // line 9: master key blob [hex]
- // IV of the master key, master key itself, master key checksum hash
+ // line 9: encryption key blob [hex]
+ // IV of the encryption key, encryption key itself, encryption key checksum hash
//
- // The master key checksum is the master key plus its checksum salt, run through
+ // The encryption key checksum is the encryption key plus its checksum salt, run through
// 10k rounds of PBKDF2. This is used to verify that the user has supplied the
- // correct password for decrypting the archive: the master key decrypted from
+ // correct password for decrypting the archive: the encryption key decrypted from
// the archive using the user-supplied password is also run through PBKDF2 in
// this way, and if the result does not match the checksum as stored in the
// archive, then we know that the user-supplied password does not match the
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 82bed3b..e42d3bd 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -379,7 +379,7 @@
}
}
- // Sanity check: make sure we never give data to the wrong app. This
+ // Make sure we never give data to the wrong app. This
// should never happen but a little paranoia here won't go amiss.
if (okay && !pkg.equals(mAgentPackage)) {
Slog.e(TAG, "Restoring data for " + pkg
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 01b40fb..923bb08 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -212,10 +212,9 @@
return buffer.toString();
}
- private static InputStream attemptMasterKeyDecryption(String decryptPassword, String algorithm,
- byte[] userSalt, byte[] ckSalt,
- int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
- boolean doLog) {
+ private static InputStream attemptEncryptionKeyDecryption(String decryptPassword,
+ String algorithm, byte[] userSalt, byte[] ckSalt, int rounds, String userIvHex,
+ String encryptionKeyBlobHex, InputStream rawInStream, boolean doLog) {
InputStream result = null;
try {
@@ -228,31 +227,31 @@
c.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(userKey.getEncoded(), "AES"),
ivSpec);
- byte[] mkCipher = PasswordUtils.hexToByteArray(masterKeyBlobHex);
+ byte[] mkCipher = PasswordUtils.hexToByteArray(encryptionKeyBlobHex);
byte[] mkBlob = c.doFinal(mkCipher);
- // first, the master key IV
+ // first, the encryption key IV
int offset = 0;
int len = mkBlob[offset++];
IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
offset += len;
- // then the master key itself
+ // then the encryption key itself
len = mkBlob[offset++];
- byte[] mk = Arrays.copyOfRange(mkBlob,
+ byte[] encryptionKey = Arrays.copyOfRange(mkBlob,
offset, offset + len);
offset += len;
- // and finally the master key checksum hash
+ // and finally the encryption key checksum hash
len = mkBlob[offset++];
byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
offset, offset + len);
- // now validate the decrypted master key against the checksum
- byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, mk, ckSalt,
+ // now validate the decrypted encryption key against the checksum
+ byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, encryptionKey, ckSalt,
rounds);
if (Arrays.equals(calculatedCk, mkChecksum)) {
ivSpec = new IvParameterSpec(IV);
c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(mk, "AES"),
+ new SecretKeySpec(encryptionKey, "AES"),
ivSpec);
// Only if all of the above worked properly will 'result' be assigned
result = new CipherInputStream(rawInStream, c);
@@ -265,7 +264,7 @@
}
} catch (BadPaddingException e) {
// This case frequently occurs when the wrong password is used to decrypt
- // the master key. Use the identical "incorrect password" log text as is
+ // the encryption key. Use the identical "incorrect password" log text as is
// used in the checksum failure log in order to avoid providing additional
// information to an attacker.
if (doLog) {
@@ -273,7 +272,7 @@
}
} catch (IllegalBlockSizeException e) {
if (doLog) {
- Slog.w(TAG, "Invalid block size in master key");
+ Slog.w(TAG, "Invalid block size in encryption key");
}
} catch (NoSuchAlgorithmException e) {
if (doLog) {
@@ -309,15 +308,15 @@
int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
String userIvHex = readHeaderLine(rawInStream); // 8
- String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
+ String encryptionKeyBlobHex = readHeaderLine(rawInStream); // 9
- // decrypt the master key blob
- result = attemptMasterKeyDecryption(decryptPassword, PBKDF_CURRENT,
- userSalt, ckSalt, rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
+ // decrypt the encryption key blob
+ result = attemptEncryptionKeyDecryption(decryptPassword, PBKDF_CURRENT, userSalt,
+ ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream, false);
if (result == null && pbkdf2Fallback) {
- result = attemptMasterKeyDecryption(
+ result = attemptEncryptionKeyDecryption(
decryptPassword, PBKDF_FALLBACK, userSalt, ckSalt,
- rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
+ rounds, userIvHex, encryptionKeyBlobHex, rawInStream, true);
}
} else {
Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 1629215..ee05c2b 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -37,7 +37,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
import com.android.server.backup.transport.TransportClient;
import com.google.android.collect.Sets;
@@ -49,8 +48,8 @@
*/
public class BackupEligibilityRules {
private static final boolean DEBUG = false;
- // Whitelist of system packages that are eligible for backup in non-system users.
- private static final Set<String> systemPackagesWhitelistedForAllUsers =
+ // List of system packages that are eligible for backup in non-system users.
+ private static final Set<String> systemPackagesAllowedForAllUsers =
Sets.newArraySet(PACKAGE_MANAGER_SENTINEL, PLATFORM_PACKAGE_NAME);
private final PackageManager mPackageManager;
@@ -97,9 +96,10 @@
// 2. they run as a system-level uid
if (UserHandle.isCore(app.uid)) {
- // and the backup is happening for non-system user on a non-whitelisted package.
+ // and the backup is happening for a non-system user on a package that is not explicitly
+ // allowed.
if (mUserId != UserHandle.USER_SYSTEM
- && !systemPackagesWhitelistedForAllUsers.contains(app.packageName)) {
+ && !systemPackagesAllowedForAllUsers.contains(app.packageName)) {
return false;
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6d8f9a3..eb38f51 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -28,6 +28,7 @@
import static java.util.concurrent.TimeUnit.MINUTES;
import android.annotation.CheckResult;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -84,6 +85,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.wm.ActivityTaskManagerInternal;
import org.xmlpull.v1.XmlPullParser;
@@ -189,7 +191,8 @@
}
@Override
- public void onUnlockUser(int userHandle) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ int userHandle = user.getUserIdentifier();
Set<Association> associations = readAllAssociations(userHandle);
if (associations == null || associations.isEmpty()) {
return;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 64d0e91..1093515 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -128,6 +128,7 @@
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
"dnsresolver_aidl_interface-java",
+ "icu4j_calendar_astronomer",
"netd_aidl_interfaces-platform-java",
"overlayable_policy_aidl-java",
"SurfaceFlingerProperties",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index b241bd1..ad1986a6 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -69,6 +69,7 @@
public static final int PACKAGE_WIFI = 13;
public static final int PACKAGE_COMPANION = 14;
public static final int PACKAGE_RETAIL_DEMO = 15;
+ public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16;
@IntDef(flag = true, prefix = "RESOLVE_", value = {
RESOLVE_NON_BROWSER_ONLY,
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index f1d74bb..a3c04be 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -59,16 +59,16 @@
/** Resolves the work source of an incoming binder transaction. */
static class AuthorizedWorkSourceProvider implements BinderInternal.WorkSourceProvider {
- private ArraySet<Integer> mAppIdWhitelist;
+ private ArraySet<Integer> mAppIdTrustlist;
AuthorizedWorkSourceProvider() {
- mAppIdWhitelist = new ArraySet<>();
+ mAppIdTrustlist = new ArraySet<>();
}
public int resolveWorkSourceUid(int untrustedWorkSourceUid) {
final int callingUid = getCallingUid();
final int appId = UserHandle.getAppId(callingUid);
- if (mAppIdWhitelist.contains(appId)) {
+ if (mAppIdTrustlist.contains(appId)) {
final int workSource = untrustedWorkSourceUid;
final boolean isWorkSourceSet = workSource != Binder.UNSET_WORKSOURCE;
return isWorkSourceSet ? workSource : callingUid;
@@ -77,13 +77,13 @@
}
public void systemReady(Context context) {
- mAppIdWhitelist = createAppidWhitelist(context);
+ mAppIdTrustlist = createAppidTrustlist(context);
}
public void dump(PrintWriter pw, AppIdToPackageMap packageMap) {
pw.println("AppIds of apps that can set the work source:");
- final ArraySet<Integer> whitelist = mAppIdWhitelist;
- for (Integer appId : whitelist) {
+ final ArraySet<Integer> trustlist = mAppIdTrustlist;
+ for (Integer appId : trustlist) {
pw.println("\t- " + packageMap.mapAppId(appId));
}
}
@@ -92,12 +92,12 @@
return Binder.getCallingUid();
}
- private ArraySet<Integer> createAppidWhitelist(Context context) {
- // Use a local copy instead of mAppIdWhitelist to prevent concurrent read access.
- final ArraySet<Integer> whitelist = new ArraySet<>();
+ private ArraySet<Integer> createAppidTrustlist(Context context) {
+ // Use a local copy instead of mAppIdTrustlist to prevent concurrent read access.
+ final ArraySet<Integer> trustlist = new ArraySet<>();
// We trust our own process.
- whitelist.add(UserHandle.getAppId(Process.myUid()));
+ trustlist.add(UserHandle.getAppId(Process.myUid()));
// We only need to initialize it once. UPDATE_DEVICE_STATS is a system permission.
final PackageManager pm = context.getPackageManager();
final String[] permissions = { android.Manifest.permission.UPDATE_DEVICE_STATS };
@@ -110,12 +110,12 @@
try {
final int uid = pm.getPackageUid(pkgInfo.packageName, queryFlags);
final int appId = UserHandle.getAppId(uid);
- whitelist.add(appId);
+ trustlist.add(appId);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Cannot find uid for package name " + pkgInfo.packageName, e);
}
}
- return whitelist;
+ return trustlist;
}
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 2e4d44c..f372c6f 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -96,6 +96,8 @@
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final String BLUETOOTH_PRIVILEGED =
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED;
private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
@@ -306,6 +308,9 @@
};
public boolean onFactoryReset() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+ "Need BLUETOOTH_PRIVILEGED permission");
+
// Wait for stable state if bluetooth is temporary state.
int state = getState();
if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 0bcd937..1a1eecd 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -16,10 +16,14 @@
package com.android.server;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.UserManager;
+import com.android.server.SystemService.TargetUser;
+
class BluetoothService extends SystemService {
private BluetoothManagerService mBluetoothManagerService;
private boolean mInitialized = false;
@@ -52,16 +56,16 @@
}
@Override
- public void onSwitchUser(int userHandle) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
if (!mInitialized) {
initialize();
} else {
- mBluetoothManagerService.handleOnSwitchUser(userHandle);
+ mBluetoothManagerService.handleOnSwitchUser(to.getUserIdentifier());
}
}
@Override
- public void onUnlockUser(int userHandle) {
- mBluetoothManagerService.handleOnUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mBluetoothManagerService.handleOnUnlockUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index c87dcd7..b3d4085 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,6 +38,7 @@
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;
@@ -457,6 +458,8 @@
}
} else if (launchPanic) {
Slog.i(TAG, "Panic gesture detected, launching panic.");
+ launchPanic = handlePanicButtonGesture();
+ // TODO(b/160006048): Add logging
}
mMetricsLogger.histogram("power_consecutive_short_tap_count",
mPowerButtonSlowConsecutiveTaps);
@@ -501,6 +504,46 @@
}
}
+ /**
+ * @return true if panic ui was launched, false otherwise.
+ */
+ @VisibleForTesting
+ boolean handlePanicButtonGesture() {
+ // TODO(b/160006048): This is the wrong way to launch panic ui. Rewrite this to go
+ // through SysUI
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "GestureLauncher:handlePanicButtonGesture");
+ try {
+ boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ if (!userSetupComplete) {
+ if (DBG) {
+ Slog.d(TAG, String.format(
+ "userSetupComplete = %s, ignoring panic gesture.",
+ userSetupComplete));
+ }
+ return false;
+ }
+ if (DBG) {
+ Slog.d(TAG, String.format(
+ "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.
+ return true;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..a3bcbbe 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.UID_OBSERVER_GONE;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -60,6 +61,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.SystemService.TargetUser;
import com.android.server.wm.ActivityTaskManagerInternal;
import dalvik.system.DexFile;
@@ -236,16 +238,18 @@
* individual apps. Make sure that user's preference is pinned into memory.
*/
@Override
- public void onSwitchUser(int userHandle) {
- if (!mUserManager.isManagedProfile(userHandle)) {
- sendPinAppsMessage(userHandle);
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ int userId = to.getUserIdentifier();
+ if (!mUserManager.isManagedProfile(userId)) {
+ sendPinAppsMessage(userId);
}
}
@Override
- public void onUnlockUser(int userHandle) {
- if (!mUserManager.isManagedProfile(userHandle)) {
- sendPinAppsMessage(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ int userId = user.getUserIdentifier();
+ if (!mUserManager.isManagedProfile(userId)) {
+ sendPinAppsMessage(userId);
}
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index e5d0021..0038dc2 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -80,10 +80,16 @@
default void onError() {}
}
+ /** Function to run on binder interface when first bound. */
+ public interface OnBindRunner {
+ /** Called to run client code with the binder. */
+ void run(IBinder binder, ComponentName service) throws RemoteException;
+ }
+
/**
* Information on the service ServiceWatcher has selected as the best option for binding.
*/
- public static final class ServiceInfo implements Comparable<ServiceInfo> {
+ private static final class ServiceInfo implements Comparable<ServiceInfo> {
public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
UserHandle.USER_NULL, false);
@@ -179,25 +185,25 @@
private final Handler mHandler;
private final Intent mIntent;
- @Nullable private final BinderRunner mOnBind;
+ @Nullable private final OnBindRunner mOnBind;
@Nullable private final Runnable mOnUnbind;
// read/write from handler thread only
private int mCurrentUserId;
// write from handler thread only, read anywhere
- private volatile ServiceInfo mServiceInfo;
+ private volatile ServiceInfo mTargetService;
private volatile IBinder mBinder;
public ServiceWatcher(Context context, String action,
- @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
+ @Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
this(context, FgThread.getHandler(), action, onBind, onUnbind, enableOverlayResId,
nonOverlayPackageResId);
}
public ServiceWatcher(Context context, Handler handler, String action,
- @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
+ @Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
mContext = context;
mHandler = handler;
@@ -214,7 +220,7 @@
mCurrentUserId = UserHandle.USER_NULL;
- mServiceInfo = ServiceInfo.NONE;
+ mTargetService = ServiceInfo.NONE;
mBinder = null;
}
@@ -304,7 +310,7 @@
}
}
- if (forceRebind || !bestServiceInfo.equals(mServiceInfo)) {
+ if (forceRebind || !bestServiceInfo.equals(mTargetService)) {
rebind(bestServiceInfo);
}
}
@@ -312,32 +318,32 @@
private void rebind(ServiceInfo newServiceInfo) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- if (!mServiceInfo.equals(ServiceInfo.NONE)) {
+ if (!mTargetService.equals(ServiceInfo.NONE)) {
if (D) {
- Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mServiceInfo);
+ Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService);
}
mContext.unbindService(this);
- onServiceDisconnected(mServiceInfo.component);
- mServiceInfo = ServiceInfo.NONE;
+ onServiceDisconnected(mTargetService.component);
+ mTargetService = ServiceInfo.NONE;
}
- mServiceInfo = newServiceInfo;
- if (mServiceInfo.equals(ServiceInfo.NONE)) {
+ mTargetService = newServiceInfo;
+ if (mTargetService.equals(ServiceInfo.NONE)) {
return;
}
- Preconditions.checkState(mServiceInfo.component != null);
+ Preconditions.checkState(mTargetService.component != null);
if (D) {
- Log.i(TAG, getLogPrefix() + " binding to " + mServiceInfo);
+ Log.i(TAG, getLogPrefix() + " binding to " + mTargetService);
}
- Intent bindIntent = new Intent(mIntent).setComponent(mServiceInfo.component);
+ Intent bindIntent = new Intent(mIntent).setComponent(mTargetService.component);
if (!mContext.bindServiceAsUser(bindIntent, this,
BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
- mHandler, UserHandle.of(mServiceInfo.userId))) {
- mServiceInfo = ServiceInfo.NONE;
+ mHandler, UserHandle.of(mTargetService.userId))) {
+ mTargetService = ServiceInfo.NONE;
Log.e(TAG, getLogPrefix() + " unexpected bind failure - retrying later");
mHandler.postDelayed(() -> onBestServiceChanged(false), RETRY_DELAY_MS);
}
@@ -355,11 +361,11 @@
mBinder = binder;
if (mOnBind != null) {
try {
- mOnBind.run(binder);
+ mOnBind.run(binder, component);
} catch (RuntimeException | RemoteException e) {
// binders may propagate some specific non-RemoteExceptions from the other side
// through the binder as well - we cannot allow those to crash the system server
- Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
+ Log.e(TAG, getLogPrefix() + " exception running on " + component, e);
}
}
}
@@ -406,7 +412,7 @@
void onPackageChanged(String packageName) {
// force a rebind if the changed package was the currently connected package
- onBestServiceChanged(packageName.equals(mServiceInfo.getPackageName()));
+ onBestServiceChanged(packageName.equals(mTargetService.getPackageName()));
}
/**
@@ -425,7 +431,7 @@
} catch (RuntimeException | RemoteException e) {
// binders may propagate some specific non-RemoteExceptions from the other side
// through the binder as well - we cannot allow those to crash the system server
- Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
+ Log.e(TAG, getLogPrefix() + " exception running on " + mTargetService, e);
runner.onError();
}
});
@@ -437,14 +443,14 @@
@Override
public String toString() {
- return mServiceInfo.toString();
+ return mTargetService.toString();
}
/**
* Dump for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("service=" + mServiceInfo);
+ pw.println("target service=" + mTargetService);
pw.println("connected=" + (mBinder != null));
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1520dd3..eca6036 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -55,6 +55,7 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -152,6 +153,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.Installer;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
@@ -259,23 +261,23 @@
}
@Override
- public void onSwitchUser(int userHandle) {
- mStorageManagerService.mCurrentUserId = userHandle;
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mStorageManagerService.mCurrentUserId = to.getUserIdentifier();
}
@Override
- public void onUnlockUser(int userHandle) {
- mStorageManagerService.onUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mStorageManagerService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onCleanupUser(int userHandle) {
- mStorageManagerService.onCleanupUser(userHandle);
+ public void onUserStopped(@NonNull TargetUser user) {
+ mStorageManagerService.onCleanupUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mStorageManagerService.onStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mStorageManagerService.onStopUser(user.getUserIdentifier());
}
@Override
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 45d53a1..1496e92 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
-import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.UserInfo;
@@ -263,26 +262,6 @@
}
/**
- * @deprecated subclasses should extend {@link #onUserStarting(TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onStartUser(@UserIdInt int userId) {}
-
- /**
- * @deprecated subclasses should extend {@link #onUserStarting(TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onStartUser(@NonNull UserInfo userInfo) {
- onStartUser(userInfo.id);
- }
-
- /**
* Called when a new user is starting, for system services to initialize any per-user
* state they maintain for running users.
*
@@ -292,27 +271,6 @@
* @param user target user
*/
public void onUserStarting(@NonNull TargetUser user) {
- onStartUser(user.getUserInfo());
- }
-
- /**
- * @deprecated subclasses should extend {@link #onUserUnlocking(TargetUser)} instead (which by
- * default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onUnlockUser(@UserIdInt int userId) {}
-
- /**
- * @deprecated subclasses should extend {@link #onUserUnlocking(TargetUser)} instead (which by
- * default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onUnlockUser(@NonNull UserInfo userInfo) {
- onUnlockUser(userInfo.id);
}
/**
@@ -333,7 +291,6 @@
* @param user target user
*/
public void onUserUnlocking(@NonNull TargetUser user) {
- onUnlockUser(user.getUserInfo());
}
/**
@@ -348,26 +305,6 @@
}
/**
- * @deprecated subclasses should extend {@link #onUserSwitching(TargetUser, TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onSwitchUser(@UserIdInt int toUserId) {}
-
- /**
- * @deprecated subclasses should extend {@link #onUserSwitching(TargetUser, TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onSwitchUser(@Nullable UserInfo from, @NonNull UserInfo to) {
- onSwitchUser(to.id);
- }
-
- /**
* Called when switching to a different foreground user, for system services that have
* special behavior for whichever user is currently in the foreground. This is called
* before any application processes are aware of the new user.
@@ -382,28 +319,6 @@
* @param to the user switching to
*/
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
- onSwitchUser((from == null ? null : from.getUserInfo()), to.getUserInfo());
- }
-
- /**
- * @deprecated subclasses should extend {@link #onUserStopping(TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onStopUser(@UserIdInt int userId) {}
-
- /**
- * @deprecated subclasses should extend {@link #onUserStopping(TargetUser)} instead
- * (which by default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onStopUser(@NonNull UserInfo user) {
- onStopUser(user.id);
-
}
/**
@@ -420,27 +335,6 @@
* @param user target user
*/
public void onUserStopping(@NonNull TargetUser user) {
- onStopUser(user.getUserInfo());
- }
-
- /**
- * @deprecated subclasses should extend {@link #onUserStopped(TargetUser)} instead (which by
- * default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onCleanupUser(@UserIdInt int userId) {}
-
- /**
- * @deprecated subclasses should extend {@link #onUserStopped(TargetUser)} instead (which by
- * default calls this method).
- *
- * @hide
- */
- @Deprecated
- public void onCleanupUser(@NonNull UserInfo user) {
- onCleanupUser(user.id);
}
/**
@@ -454,7 +348,6 @@
* @param user target user
*/
public void onUserStopped(@NonNull TargetUser user) {
- onCleanupUser(user.getUserInfo());
}
/**
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a4c6c87..7381da1 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -111,11 +111,11 @@
* Change-Id: I450c968bda93767554b5188ee63e10c9f43c5aa4 fixes bugs 16148026
* and 15973975 by saving the phoneId of the registrant and then using the
* phoneId when deciding to to make a callback. This is necessary because
- * a subId changes from to a dummy value when a SIM is removed and thus won't
+ * a subId changes from to a placeholder value when a SIM is removed and thus won't
* compare properly. Because getPhoneIdFromSubId(int subId) handles
- * the dummy value conversion we properly do the callbacks.
+ * the placeholder value conversion we properly do the callbacks.
*
- * Eventually we may want to remove the notion of dummy value but for now this
+ * Eventually we may want to remove the notion of placeholder value but for now this
* looks like the best approach.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1800,7 +1800,9 @@
mPreciseDataConnectionStates.get(phoneId).put(
apnType,
new PreciseDataConnectionState.Builder()
- .setApnTypes(apnType)
+ .setApnSetting(new ApnSetting.Builder()
+ .setApnTypeBitmask(apnType)
+ .build())
.build());
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
@@ -1984,7 +1986,9 @@
mPreciseDataConnectionStates.get(phoneId).put(
apnType,
new PreciseDataConnectionState.Builder()
- .setApnTypes(apnType)
+ .setApnSetting(new ApnSetting.Builder()
+ .setApnTypeBitmask(apnType)
+ .build())
.setFailCause(failCause)
.build());
for (Record r : mRecords) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 915189c..df9dee89 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -16,7 +16,15 @@
package com.android.server;
+import static android.app.UiModeManager.DEFAULT_PRIORITY;
+import static android.app.UiModeManager.MODE_NIGHT_AUTO;
+import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
+import static android.app.UiModeManager.MODE_NIGHT_YES;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.util.TimeUtils.isTimeBetween;
+
import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
@@ -64,6 +72,7 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService.TargetUser;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -81,13 +90,6 @@
import java.util.Map;
import java.util.Set;
-import static android.app.UiModeManager.DEFAULT_PRIORITY;
-import static android.app.UiModeManager.MODE_NIGHT_AUTO;
-import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
-import static android.app.UiModeManager.MODE_NIGHT_YES;
-import static android.os.UserHandle.USER_SYSTEM;
-import static android.util.TimeUtils.isTimeBetween;
-
final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
private static final boolean LOG = false;
@@ -322,8 +324,7 @@
}
@Override
- public void onSwitchUser(int userHandle) {
- super.onSwitchUser(userHandle);
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
verifySetupWizardCompleted();
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 7dc0b3a..35e88eb 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -106,6 +106,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -161,14 +162,14 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- mService.onUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- Slog.i(TAG, "onStopUser " + userHandle);
- mService.purgeUserData(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ Slog.i(TAG, "onStopUser " + user);
+ mService.purgeUserData(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 33a92e6..1680963 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2559,12 +2559,12 @@
private int getAllowMode(Intent service, @Nullable String callingPackage) {
if (callingPackage == null || service.getComponent() == null) {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
}
if (callingPackage.equals(service.getComponent().getPackageName())) {
- return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
} else {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cca2654..c187772 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -341,6 +341,7 @@
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
import com.android.server.UserspaceRebootLogger;
@@ -2333,8 +2334,8 @@
}
@Override
- public void onCleanupUser(int userId) {
- mService.mBatteryStatsService.onCleanupUser(userId);
+ public void onUserStopped(@NonNull TargetUser user) {
+ mService.mBatteryStatsService.onCleanupUser(user.getUserIdentifier());
}
public ActivityManagerService getService() {
@@ -2443,7 +2444,7 @@
? Collections.emptyList()
: Arrays.asList(exemptions.split(","));
}
- if (!ZYGOTE_PROCESS.setApiBlacklistExemptions(mExemptions)) {
+ if (!ZYGOTE_PROCESS.setApiDenylistExemptions(mExemptions)) {
Slog.e(TAG, "Failed to set API blacklist exemptions!");
// leave mExemptionsStr as is, so we don't try to send the same list again.
mExemptions = Collections.emptyList();
@@ -13394,7 +13395,7 @@
// XXX Commented out for now. Trying to figure out a way to reproduce
// the actual situation to identify what is actually going on.
if (false) {
- mCpHelper.cleanupLaunchingProviders();
+ mCpHelper.cleanupLaunchingProvidersLocked();
}
skipCurrentReceiverLocked(app);
@@ -14286,7 +14287,7 @@
}
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
- int callingUid, int[] users, int[] broadcastWhitelist) {
+ int callingUid, int[] users, int[] broadcastAllowList) {
// TODO: come back and remove this assumption to triage all broadcasts
int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
@@ -14362,12 +14363,12 @@
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
- if (receivers != null && broadcastWhitelist != null) {
+ if (receivers != null && broadcastAllowList != null) {
for (int i = receivers.size() - 1; i >= 0; i--) {
final int receiverAppId = UserHandle.getAppId(
receivers.get(i).activityInfo.applicationInfo.uid);
if (receiverAppId >= Process.FIRST_APPLICATION_UID
- && Arrays.binarySearch(broadcastWhitelist, receiverAppId) < 0) {
+ && Arrays.binarySearch(broadcastAllowList, receiverAppId) < 0) {
receivers.remove(i);
}
}
@@ -14477,7 +14478,7 @@
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken,
- @Nullable int[] broadcastWhitelist) {
+ @Nullable int[] broadcastAllowList) {
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14486,10 +14487,10 @@
intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
- if (userId == UserHandle.USER_ALL && broadcastWhitelist != null) {
- Slog.e(TAG, "broadcastWhitelist only applies when sending to individual users. "
+ if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
+ Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "
+ "Assuming restrictive whitelist.");
- broadcastWhitelist = new int[]{};
+ broadcastAllowList = new int[]{};
}
// By default broadcasts do not go to stopped apps.
@@ -14981,7 +14982,7 @@
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(
- intent, resolvedType, callingUid, users, broadcastWhitelist);
+ intent, resolvedType, callingUid, users, broadcastAllowList);
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
@@ -15011,13 +15012,13 @@
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
- if (registeredReceivers != null && broadcastWhitelist != null) {
+ if (registeredReceivers != null && broadcastAllowList != null) {
// if a uid whitelist was provided, remove anything in the application space that wasn't
// in it.
for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
if (owningAppId >= Process.FIRST_APPLICATION_UID
- && Arrays.binarySearch(broadcastWhitelist, owningAppId) < 0) {
+ && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
registeredReceivers.remove(i);
}
}
@@ -17996,7 +17997,7 @@
public int broadcastIntent(Intent intent,
IIntentReceiver resultTo,
String[] requiredPermissions,
- boolean serialized, int userId, int[] appIdWhitelist) {
+ boolean serialized, int userId, int[] appIdAllowList) {
synchronized (ActivityManagerService.this) {
intent = verifyBroadcastLocked(intent);
@@ -18011,7 +18012,7 @@
null /*options*/, serialized, false /*sticky*/, callingPid, callingUid,
callingUid, callingPid, userId, false /*allowBackgroundStarts*/,
null /*tokenNeededForBackgroundActivityStarts*/,
- appIdWhitelist);
+ appIdAllowList);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 43e3a04..d9fde0f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -16,8 +16,6 @@
package com.android.server.am;
-import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
-
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -256,7 +254,7 @@
ProcessDependencies processDependencies) {
mAm = am;
mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread",
- THREAD_PRIORITY_FOREGROUND, true);
+ Process.THREAD_GROUP_SYSTEM, true);
mProcStateThrottle = new HashSet<>();
mProcessDependencies = processDependencies;
mTestCallback = callback;
@@ -280,8 +278,6 @@
updateProcStateThrottle();
updateUseFreezer();
}
- Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
- Process.THREAD_GROUP_SYSTEM);
}
/**
@@ -411,12 +407,15 @@
mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
- if (mUseCompaction) {
+ if (mUseCompaction && mCompactionHandler == null) {
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
mCompactionHandler = new MemCompactionHandler();
+
+ Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
+ Process.THREAD_GROUP_SYSTEM);
}
}
@@ -470,13 +469,16 @@
mUseFreezer = isFreezerSupported();
}
- if (mUseFreezer) {
+ if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
mFreezeHandler = new FreezeHandler();
+
+ Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
+ Process.THREAD_GROUP_SYSTEM);
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 1e0c243..5cc7aba 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -15,19 +15,15 @@
*/
package com.android.server.am;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.PROC_CHAR;
import static android.os.Process.PROC_OUT_LONG;
import static android.os.Process.PROC_PARENS;
import static android.os.Process.PROC_SPACE_TERM;
import static android.os.Process.SYSTEM_UID;
-import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
-import static android.os.Process.readProcFile;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerService.TAG_MU;
-import android.Manifest;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -80,11 +76,7 @@
public class ContentProviderHelper {
private static final String TAG = "ContentProviderHelper";
- private ActivityManagerService mService;
-
- private boolean mSystemProvidersInstalled;
-
- private final ProviderMap mProviderMap;
+ private final ActivityManagerService mService;
/**
* List of content providers who have clients waiting for them. The
@@ -92,6 +84,8 @@
* removed from this list once it is published.
*/
private final ArrayList<ContentProviderRecord> mLaunchingProviders = new ArrayList<>();
+ private final ProviderMap mProviderMap;
+ private boolean mSystemProvidersInstalled;
ContentProviderHelper(ActivityManagerService service, boolean createProviderMap) {
mService = service;
@@ -102,193 +96,852 @@
return mProviderMap;
}
- List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
- List<ProviderInfo> providers = null;
- try {
- providers = AppGlobals.getPackageManager().queryContentProviders(
- app.processName, app.uid, ActivityManagerService.STOCK_PM_FLAGS
- | PackageManager.GET_URI_PERMISSION_PATTERNS
- | PackageManager.MATCH_DIRECT_BOOT_AUTO, /*metaDataKey=*/ null)
- .getList();
- } catch (RemoteException ex) {
+ ContentProviderHolder getContentProvider(IApplicationThread caller, String callingPackage,
+ String name, int userId, boolean stable) {
+ mService.enforceNotIsolatedCaller("getContentProvider");
+ if (caller == null) {
+ String msg = "null IApplicationThread when getting content provider " + name;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
}
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+ // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
+ // with cross-user grant.
+ final int callingUid = Binder.getCallingUid();
+ if (callingPackage != null && mService.mAppOpsService.checkPackage(
+ callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException("Given calling package " + callingPackage
+ + " does not match caller's uid " + callingUid);
}
- int userId = app.userId;
- if (providers != null) {
- int N = providers.size();
- app.pubProviders.ensureCapacity(N + app.pubProviders.size());
- for (int i = 0; i < N; i++) {
- // TODO: keep logic in sync with installEncryptionUnawareProviders
- ProviderInfo cpi = (ProviderInfo) providers.get(i);
- boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags);
- if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
- // This is a singleton provider, but a user besides the
- // default user is asking to initialize a process it runs
- // in... well, no, it doesn't actually run in this process,
- // it runs in the process of the default user. Get rid of it.
- providers.remove(i);
- N--;
- i--;
- continue;
+ return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
+ null, stable, userId);
+ }
+
+ ContentProviderHolder getContentProviderExternal(
+ String name, int userId, IBinder token, String tag) {
+ mService.enforceCallingPermission(
+ android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call getContentProviderExternal()");
+ userId = mService.mUserController.handleIncomingUser(
+ Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, ActivityManagerInternal.ALLOW_FULL_ONLY, "getContentProvider", null);
+ return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(),
+ tag != null ? tag : "*external*", userId);
+ }
+
+ ContentProviderHolder getContentProviderExternalUnchecked(String name,
+ IBinder token, int callingUid, String callingTag, int userId) {
+ return getContentProviderImpl(null, name, token, callingUid, null, callingTag,
+ true, userId);
+ }
+
+ private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
+ String name, IBinder token, int callingUid, String callingPackage, String callingTag,
+ boolean stable, int userId) {
+ ContentProviderRecord cpr;
+ ContentProviderConnection conn = null;
+ ProviderInfo cpi = null;
+ boolean providerRunning = false;
+ synchronized (mService) {
+ long startTime = SystemClock.uptimeMillis();
+
+ ProcessRecord r = null;
+ if (caller != null) {
+ r = mService.getRecordForAppLocked(caller);
+ if (r == null) {
+ throw new SecurityException("Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid() + ") when getting content provider "
+ + name);
+ }
+ }
+
+ boolean checkCrossUser = true;
+
+ checkTime(startTime, "getContentProviderImpl: getProviderByName");
+
+ // First check if this content provider has been published...
+ cpr = mProviderMap.getProviderByName(name, userId);
+ // If that didn't work, check if it exists for user 0 and then
+ // verify that it's a singleton provider before using it.
+ if (cpr == null && userId != UserHandle.USER_SYSTEM) {
+ cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
+ if (cpr != null) {
+ cpi = cpr.info;
+ if (mService.isSingleton(
+ cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
+ && mService.isValidSingletonCall(
+ r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) {
+ userId = UserHandle.USER_SYSTEM;
+ checkCrossUser = false;
+ } else {
+ cpr = null;
+ cpi = null;
+ }
+ }
+ }
+
+ ProcessRecord dyingProc = null;
+ if (cpr != null && cpr.proc != null) {
+ providerRunning = !cpr.proc.killed;
+
+ // Note if killedByAm is also set, this means the provider process has just been
+ // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
+ // yet. So we need to call appDiedLocked() here and let it clean up.
+ // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
+ // how to test this case.)
+ if (cpr.proc.killed && cpr.proc.killedByAm) {
+ Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
+ // Now we are going to wait for the death before starting the new process.
+ dyingProc = cpr.proc;
+ }
+ }
+
+ if (providerRunning) {
+ cpi = cpr.info;
+ String msg;
+
+ if (r != null && cpr.canRunHere(r)) {
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup "
+ + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ // This provider has been published or is in the process
+ // of being published... but it is also allowed to run
+ // in the caller's process, so don't make a connection
+ // and just let the caller instantiate its own instance.
+ ContentProviderHolder holder = cpr.newHolder(null);
+ // don't give caller the provider object, it needs to make its own.
+ holder.provider = null;
+ return holder;
+ }
+
+ // Don't expose providers between normal apps and instant apps
+ try {
+ if (AppGlobals.getPackageManager()
+ .resolveContentProvider(name, /*flags=*/ 0, userId) == null) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ }
+
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException(
+ "Content provider lookup " + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ final long origId = Binder.clearCallingIdentity();
+
+ checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
+
+ // In this case the provider instance already exists, so we can
+ // return it right away.
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
+ stable, true, startTime, mService.mProcessList);
+
+ checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
+ final int verifiedAdj = cpr.proc.verifiedAdj;
+ boolean success = mService.updateOomAdjLocked(cpr.proc, true,
+ OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
+ // XXX things have changed so updateOomAdjLocked doesn't actually tell us
+ // if the process has been successfully adjusted. So to reduce races with
+ // it, we will check whether the process still exists. Note that this doesn't
+ // completely get rid of races with LMK killing the process, but should make
+ // them much smaller.
+ if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
+ success = false;
+ }
+ maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
+ checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.i(TAG, "Adjust success: " + success);
+ }
+ // NOTE: there is still a race here where a signal could be
+ // pending on the process even though we managed to update its
+ // adj level. Not sure what to do about this, but at least
+ // the race is now smaller.
+ if (!success) {
+ // Uh oh... it looks like the provider's process
+ // has been killed on us. We need to wait for a new
+ // process to be started, and make sure its death
+ // doesn't kill our process.
+ Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ + " is crashing; detaching " + r);
+ boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
+ if (!lastRef) {
+ // This wasn't the last ref our process had on
+ // the provider... we will be killed during cleaning up, bail.
+ return null;
+ }
+ // We'll just start a new process to host the content provider
+ providerRunning = false;
+ conn = null;
+ dyingProc = cpr.proc;
+ } else {
+ cpr.proc.verifiedAdj = cpr.proc.setAdj;
+ }
+
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ if (!providerRunning) {
+ try {
+ checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
+ cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
+ ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.GET_URI_PERMISSION_PATTERNS,
+ userId);
+ checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
+ } catch (RemoteException ex) {
+ }
+ if (cpi == null) {
+ return null;
+ }
+ // If the provider is a singleton AND
+ // (it's a call within the same user || the provider is a privileged app)
+ // Then allow connecting to the singleton provider
+ boolean singleton = mService.isSingleton(
+ cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
+ && mService.isValidSingletonCall(
+ r == null ? callingUid : r.uid, cpi.applicationInfo.uid);
+ if (singleton) {
+ userId = UserHandle.USER_SYSTEM;
+ }
+ cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
+ checkTime(startTime, "getContentProviderImpl: got app info for user");
+
+ String msg;
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup " + name
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
+ // If this content provider does not run in the system
+ // process, and the system is not yet ready to run other
+ // processes, then fail fast instead of hanging.
+ throw new IllegalArgumentException(
+ "Attempt to launch content provider before system ready");
+ }
+
+ // If system providers are not installed yet we aggressively crash to avoid
+ // creating multiple instance of these providers and then bad things happen!
+ if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+ && "system".equals(cpi.processName)) {
+ throw new IllegalStateException("Cannot access system provider: '"
+ + cpi.authority + "' before system providers are installed!");
+ }
+
+ // Make sure that the user who owns this provider is running. If not,
+ // we don't want to allow it to run.
+ if (!mService.mUserController.isUserRunning(userId, 0)) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + ": user " + userId + " is stopped");
+ return null;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
- ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
- if (cpr == null) {
- cpr = new ContentProviderRecord(mService, cpi, app.info, comp, singleton);
+ checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
+ cpr = mProviderMap.getProviderByClass(comp, userId);
+ checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
+ boolean firstClass = cpr == null;
+ if (firstClass) {
+ final long ident = Binder.clearCallingIdentity();
+
+ // If permissions need a review before any of the app components can run,
+ // we return no provider and launch a review activity if the calling app
+ // is in the foreground.
+ if (!requestTargetProviderPermissionsReviewIfNeededLocked(
+ cpi, r, userId, mService.mContext)) {
+ return null;
+ }
+
+ try {
+ checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ cpi.applicationInfo.packageName,
+ ActivityManagerService.STOCK_PM_FLAGS, userId);
+ checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
+ if (ai == null) {
+ Slog.w(TAG, "No package info for content provider " + cpi.name);
+ return null;
+ }
+ ai = mService.getAppInfoForUser(ai, userId);
+ cpr = new ContentProviderRecord(mService, cpi, ai, comp, singleton);
+ } catch (RemoteException ex) {
+ // pm is in same process, this will never happen.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } else if (dyingProc == cpr.proc && dyingProc != null) {
+ // The old stable connection's client should be killed during proc cleaning up,
+ // so do not re-use the old ContentProviderRecord, otherwise the new clients
+ // could get killed unexpectedly.
+ cpr = new ContentProviderRecord(cpr);
+ // This is sort of "firstClass"
+ firstClass = true;
+ }
+
+ checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
+
+ if (r != null && cpr.canRunHere(r)) {
+ // If this is a multiprocess provider, then just return its
+ // info and allow the caller to instantiate it. Only do
+ // this if the provider is the same user as the caller's
+ // process, or can run as root (so can be in any process).
+ return cpr.newHolder(null);
+ }
+
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
+ + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name
+ + " callers=" + Debug.getCallers(6));
+ }
+
+ // This is single process, and our app is now connecting to it.
+ // See if we are already in the process of launching this provider.
+ final int numLaunchingProviders = mLaunchingProviders.size();
+ int i;
+ for (i = 0; i < numLaunchingProviders; i++) {
+ if (mLaunchingProviders.get(i) == cpr) {
+ break;
+ }
+ }
+
+ // If the provider is not already being launched, then get it started.
+ if (i >= numLaunchingProviders) {
+ final long origId = Binder.clearCallingIdentity();
+
+ try {
+ // Content provider is now in use, its package can't be stopped.
+ try {
+ checkTime(startTime,
+ "getContentProviderImpl: before set stopped state");
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ cpr.appInfo.packageName, false, userId);
+ checkTime(startTime, "getContentProviderImpl: after set stopped state");
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + cpr.appInfo.packageName + ": " + e);
+ }
+
+ // Use existing process if already started
+ checkTime(startTime, "getContentProviderImpl: looking for process record");
+ ProcessRecord proc = mService.getProcessRecordLocked(
+ cpi.processName, cpr.appInfo.uid, false);
+ if (proc != null && proc.thread != null && !proc.killed) {
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.d(TAG, "Installing in existing process " + proc);
+ }
+ if (!proc.pubProviders.containsKey(cpi.name)) {
+ checkTime(startTime, "getContentProviderImpl: scheduling install");
+ proc.pubProviders.put(cpi.name, cpr);
+ try {
+ proc.thread.scheduleInstallProvider(cpi);
+ } catch (RemoteException e) {
+ }
+ }
+ } else {
+ checkTime(startTime, "getContentProviderImpl: before start process");
+ proc = mService.startProcessLocked(
+ cpi.processName, cpr.appInfo, false, 0,
+ new HostingRecord("content provider",
+ new ComponentName(
+ cpi.applicationInfo.packageName, cpi.name)),
+ Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
+ checkTime(startTime, "getContentProviderImpl: after start process");
+ if (proc == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider " + name
+ + ": process is bad");
+ return null;
+ }
+ }
+ cpr.launchingApp = proc;
+ mLaunchingProviders.add(cpr);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ checkTime(startTime, "getContentProviderImpl: updating data structures");
+
+ // Make sure the provider is published (the same provider class
+ // may be published under multiple names).
+ if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
+
+ mProviderMap.putProviderByName(name, cpr);
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
+ stable, false, startTime, mService.mProcessList);
+ if (conn != null) {
+ conn.waiting = true;
}
- app.pubProviders.put(cpi.name, cpr);
- if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
- // Don't add this if it is a platform component that is marked
- // to run in multiple processes, because this is actually
- // part of the framework so doesn't make sense to track as a
- // separate apk in the process.
- app.addPackage(cpi.applicationInfo.packageName,
- cpi.applicationInfo.longVersionCode, mService.mProcessStats);
+ }
+ checkTime(startTime, "getContentProviderImpl: done!");
+
+ mService.grantImplicitAccess(userId, null, callingUid,
+ UserHandle.getAppId(cpi.applicationInfo.uid));
+ }
+
+ // Wait for the provider to be published...
+ final long timeout =
+ SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
+ boolean timedOut = false;
+ synchronized (cpr) {
+ while (cpr.provider == null) {
+ if (cpr.launchingApp == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + ": launching app became null");
+ EventLogTags.writeAmProviderLostProcess(
+ UserHandle.getUserId(cpi.applicationInfo.uid),
+ cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name);
+ return null;
}
- mService.notifyPackageUse(cpi.applicationInfo.packageName,
- PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
+ try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "Waiting to start provider " + cpr
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
+ }
+ if (conn != null) {
+ conn.waiting = true;
+ }
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ timedOut = true;
+ break;
+ }
+ } catch (InterruptedException ex) {
+ } finally {
+ if (conn != null) {
+ conn.waiting = false;
+ }
+ }
}
}
- return providers;
+ if (timedOut) {
+ // Note we do it after releasing the lock.
+ String callerName = "unknown";
+ if (caller != null) {
+ synchronized (mService) {
+ final ProcessRecord record =
+ mService.mProcessList.getLRURecordForAppLocked(caller);
+ if (record != null) {
+ callerName = record.processName;
+ }
+ }
+ }
+
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + " providerRunning=" + providerRunning
+ + " caller=" + callerName + "/" + Binder.getCallingUid());
+ return null;
+ }
+ return cpr.newHolder(conn);
}
- @GuardedBy("mService")
- private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
- final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
- String callingPackage, String callingTag, boolean stable, boolean updateLru,
- long startTime, ProcessList processList) {
- if (r != null) {
- for (int i = 0; i < r.conProviders.size(); i++) {
- ContentProviderConnection conn = r.conProviders.get(i);
- if (conn.provider == cpr) {
- conn.incrementCount(stable);
- return conn;
- }
+ void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
+ if (providers == null) {
+ return;
+ }
+
+ mService.enforceNotIsolatedCaller("publishContentProviders");
+ synchronized (mService) {
+ final ProcessRecord r = mService.getRecordForAppLocked(caller);
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
+ }
+ if (r == null) {
+ throw new SecurityException("Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid()
+ + ") when publishing content providers");
}
- // Create a new ContentProviderConnection. The reference count
- // is known to be 1.
- ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage);
- conn.startAssociationIfNeeded();
- conn.initializeCount(stable);
- cpr.connections.add(conn);
- r.conProviders.add(conn);
- mService.startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
- cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- if (updateLru && cpr.proc != null
- && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
- // If this is a perceptible app accessing the provider, make
- // sure to count it as being accessed and thus back up on
- // the LRU list. This is good because content providers are
- // often expensive to start. The calls to checkTime() use
- // the "getContentProviderImpl" tag here, because it's part
- // of the checktime log in getContentProviderImpl().
- checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
- processList.updateLruProcessLocked(cpr.proc, false, null);
- checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
+ final long origId = Binder.clearCallingIdentity();
+
+ for (int i = 0, size = providers.size(); i < size; i++) {
+ ContentProviderHolder src = providers.get(i);
+ if (src == null || src.info == null || src.provider == null) {
+ continue;
+ }
+ ContentProviderRecord dst = r.pubProviders.get(src.info.name);
+ if (dst == null) {
+ continue;
+ }
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
+ }
+
+ ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
+ mProviderMap.putProviderByClass(comp, dst);
+ String[] names = dst.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ mProviderMap.putProviderByName(names[j], dst);
+ }
+
+ boolean wasInLaunchingProviders = false;
+ for (int j = 0, numLaunching = mLaunchingProviders.size(); j < numLaunching; j++) {
+ if (mLaunchingProviders.get(j) == dst) {
+ mLaunchingProviders.remove(j);
+ wasInLaunchingProviders = true;
+ j--;
+ numLaunching--;
+ }
+ }
+ if (wasInLaunchingProviders) {
+ mService.mHandler.removeMessages(
+ ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
+ }
+ // Make sure the package is associated with the process.
+ // XXX We shouldn't need to do this, since we have added the package
+ // when we generated the providers in generateApplicationProvidersLocked().
+ // But for some reason in some cases we get here with the package no longer
+ // added... for now just patch it in to make things happy.
+ r.addPackage(dst.info.applicationInfo.packageName,
+ dst.info.applicationInfo.longVersionCode, mService.mProcessStats);
+ synchronized (dst) {
+ dst.provider = src.provider;
+ dst.setProcess(r);
+ dst.notifyAll();
+ }
+ dst.mRestartCount = 0;
+ mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
+ maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
}
- return conn;
+
+ Binder.restoreCallingIdentity(origId);
}
- cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+ }
+
+ /**
+ * Drop a content provider from a ProcessRecord's bookkeeping
+ */
+ void removeContentProvider(IBinder connection, boolean stable) {
+ mService.enforceNotIsolatedCaller("removeContentProvider");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "removeContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+ if (decProviderCountLocked(conn, null, null, stable)) {
+ mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
+ mService.enforceCallingPermission(
+ android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call removeContentProviderExternal()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeContentProviderExternalUnchecked(name, token, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ void removeContentProviderExternalUnchecked(String name, IBinder token, int userId) {
+ synchronized (mService) {
+ ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
+ if (cpr == null) {
+ //remove from mProvidersByClass
+ if (ActivityManagerDebugConfig.DEBUG_ALL) {
+ Slog.v(TAG, name + " content provider not found in providers list");
+ }
+ return;
+ }
+
+ // update content provider record entry info
+ ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
+ ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
+ if (localCpr.hasExternalProcessHandles()) {
+ if (localCpr.removeExternalProcessHandleLocked(token)) {
+ mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ } else {
+ Slog.e(TAG, "Attempt to remove content provider " + localCpr
+ + " with no external reference for token: " + token + ".");
+ }
+ } else {
+ Slog.e(TAG, "Attempt to remove content provider: " + localCpr
+ + " with no external references.");
+ }
+ }
+ }
+
+ boolean refContentProvider(IBinder connection, int stable, int unstable) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ conn.adjustCounts(stable, unstable);
+ return !conn.dead;
+ }
+
+ void unstableProviderDied(IBinder connection) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ // Safely retrieve the content provider associated with the connection.
+ IContentProvider provider;
+ synchronized (mService) {
+ provider = conn.provider.provider;
+ }
+
+ if (provider == null) {
+ // Um, yeah, we're way ahead of you.
+ return;
+ }
+
+ // Make sure the caller is being honest with us.
+ if (provider.asBinder().pingBinder()) {
+ // Er, no, still looks good to us.
+ synchronized (mService) {
+ Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
+ + " says " + conn + " died, but we don't agree");
+ return;
+ }
+ }
+
+ // Well look at that! It's dead!
+ synchronized (mService) {
+ if (conn.provider.provider != provider) {
+ // But something changed... good enough.
+ return;
+ }
+
+ ProcessRecord proc = conn.provider.proc;
+ if (proc == null || proc.thread == null) {
+ // Seems like the process is already cleaned up.
+ return;
+ }
+
+ // As far as we're concerned, this is just like receiving a
+ // death notification... just a bit prematurely.
+ mService.reportUidInfoMessageLocked(TAG, "Process " + proc.processName
+ + " (pid " + proc.pid + ") early provider death", proc.info.uid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.appDiedLocked(proc, "unstable content provider");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ void appNotRespondingViaProvider(IBinder connection) {
+ mService.enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+ "appNotRespondingViaProvider()");
+
+ final ContentProviderConnection conn = (ContentProviderConnection) connection;
+ if (conn == null) {
+ Slog.w(TAG, "ContentProviderConnection is null");
+ return;
+ }
+
+ final ProcessRecord host = conn.provider.proc;
+ if (host == null) {
+ Slog.w(TAG, "Failed to find hosting ProcessRecord");
+ return;
+ }
+
+ mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");
+ }
+
+ /**
+ * Allows apps to retrieve the MIME type of a URI.
+ * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+ * users, then it does not need permission to access the ContentProvider.
+ * Either, it needs cross-user uri grants.
+ *
+ * CTS tests for this functionality can be run with "runtest cts-appsecurity".
+ *
+ * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
+ * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+ *
+ * @deprecated -- use getProviderMimeTypeAsync.
+ */
+ @Deprecated
+ String getProviderMimeType(Uri uri, int userId) {
+ mService.enforceNotIsolatedCaller("getProviderMimeType");
+ final String name = uri.getAuthority();
+ int callingUid = Binder.getCallingUid();
+ int callingPid = Binder.getCallingPid();
+ long ident = 0;
+ boolean clearedIdentity = false;
+ userId = mService.mUserController.unsafeConvertIncomingUser(userId);
+ if (canClearIdentity(callingPid, callingUid, userId)) {
+ clearedIdentity = true;
+ ident = Binder.clearCallingIdentity();
+ }
+ ContentProviderHolder holder = null;
+ try {
+ holder = getContentProviderExternalUnchecked(name, null, callingUid,
+ "*getmimetype*", userId);
+ if (holder != null) {
+ final IBinder providerConnection = holder.connection;
+ final ComponentName providerName = holder.info.getComponentName();
+ // Note: creating a new Runnable instead of using a lambda here since lambdas in
+ // java provide no guarantee that there will be a new instance returned every call.
+ // Hence, it's possible that a cached copy is returned and the ANR is executed on
+ // the incorrect provider.
+ final Runnable providerNotResponding = new Runnable() {
+ @Override
+ public void run() {
+ Log.w(TAG, "Provider " + providerName + " didn't return from getType().");
+ appNotRespondingViaProvider(providerConnection);
+ }
+ };
+ mService.mHandler.postDelayed(providerNotResponding, 1000);
+ try {
+ return holder.provider.getType(uri);
+ } finally {
+ mService.mHandler.removeCallbacks(providerNotResponding);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ return null;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while determining type of " + uri, e);
+ return null;
+ } finally {
+ // We need to clear the identity to call removeContentProviderExternalUnchecked
+ if (!clearedIdentity) {
+ ident = Binder.clearCallingIdentity();
+ }
+ try {
+ if (holder != null) {
+ removeContentProviderExternalUnchecked(name, null, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
return null;
}
- @GuardedBy("mService")
- private boolean decProviderCountLocked(ContentProviderConnection conn,
- ContentProviderRecord cpr,
- IBinder externalProcessToken, boolean stable) {
- if (conn != null) {
- cpr = conn.provider;
- final int referenceCount = conn.decrementCount(stable);
- if (referenceCount == 0) {
- conn.stopAssociation();
- cpr.connections.remove(conn);
- conn.client.conProviders.remove(conn);
- if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
- // The client is more important than last activity -- note the time this
- // is happening, so we keep the old provider process around a bit as last
- // activity to avoid thrashing it.
- if (cpr.proc != null) {
- cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
+ /**
+ * Allows apps to retrieve the MIME type of a URI.
+ * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+ * users, then it does not need permission to access the ContentProvider.
+ * Either way, it needs cross-user uri grants.
+ */
+ void getProviderMimeTypeAsync(Uri uri, int userId, RemoteCallback resultCallback) {
+ mService.enforceNotIsolatedCaller("getProviderMimeTypeAsync");
+ final String name = uri.getAuthority();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
+ final long ident = canClearIdentity(callingPid, callingUid, userId)
+ ? Binder.clearCallingIdentity() : 0;
+ try {
+ final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
+ callingUid, "*getmimetype*", safeUserId);
+ if (holder != null) {
+ holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ removeContentProviderExternalUnchecked(name, null, safeUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- }
- mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
- cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- return true;
+ resultCallback.sendResult(result);
+ }));
+ } else {
+ resultCallback.sendResult(Bundle.EMPTY);
}
- return false;
- }
- cpr.removeExternalProcessHandleLocked(externalProcessToken);
- return false;
- }
-
- private static final class StartActivityRunnable implements Runnable {
- private final Context mContext;
- private final Intent mIntent;
- private final UserHandle mUserHandle;
-
- StartActivityRunnable(Context context, Intent intent, UserHandle userHandle) {
- this.mContext = context;
- this.mIntent = intent;
- this.mUserHandle = userHandle;
- }
-
- @Override
- public void run() {
- mContext.startActivityAsUser(mIntent, mUserHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ resultCallback.sendResult(Bundle.EMPTY);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
- private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
- ProcessRecord r, final int userId, Context context) {
- if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
- cpi.packageName, userId)) {
-
- final boolean callerForeground = r == null || r.setSchedGroup
- != ProcessList.SCHED_GROUP_BACKGROUND;
-
- // Show a permission review UI only for starting from a foreground app
- if (!callerForeground) {
- Slog.w(TAG, "u" + userId + " Instantiating a provider in package"
- + cpi.packageName + " requires a permissions review");
- return false;
- }
-
- final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
-
- if (ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW) {
- Slog.i(TAG, "u" + userId + " Launching permission review "
- + "for package " + cpi.packageName);
- }
-
- final UserHandle userHandle = new UserHandle(userId);
- mService.mHandler.post(new StartActivityRunnable(context, intent, userHandle));
-
- return false;
+ private boolean canClearIdentity(int callingPid, int callingUid, int userId) {
+ if (UserHandle.getUserId(callingUid) == userId) {
+ return true;
}
-
- return true;
+ return ActivityManagerService.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, callingPid,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+ || ActivityManagerService.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPid,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
}
/**
* Check if the calling UID has a possible chance at accessing the provider
* at the given authority and user.
*/
- public String checkContentProviderAccess(String authority, int userId) {
+ String checkContentProviderAccess(String authority, int userId) {
if (userId == UserHandle.USER_ALL) {
mService.mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
userId = UserHandle.getCallingUserId();
}
@@ -308,7 +961,7 @@
+ "; expected to find a valid ContentProvider for this authority";
}
- ProcessRecord r = null;
+ ProcessRecord r;
synchronized (mService.mPidsSelfLocked) {
r = mService.mPidsSelfLocked.get(Binder.getCallingPid());
}
@@ -321,13 +974,303 @@
}
}
+ int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
+ if (Thread.holdsLock(mService.mActivityTaskManager.getGlobalLock())) {
+ Slog.wtf(TAG, new IllegalStateException("Unable to check Uri permission"
+ + " because caller is holding WM lock; assuming permission denied"));
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ final String name = uri.getAuthority();
+ final long ident = Binder.clearCallingIdentity();
+ ContentProviderHolder holder = null;
+ try {
+ holder = getContentProviderExternalUnchecked(name, null, callingUid,
+ "*checkContentProviderUriPermission*", userId);
+ if (holder != null) {
+ return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ return PackageManager.PERMISSION_DENIED;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while determining type of " + uri, e);
+ return PackageManager.PERMISSION_DENIED;
+ } finally {
+ try {
+ if (holder != null) {
+ removeContentProviderExternalUnchecked(name, null, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ @GuardedBy("mService")
+ void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
+ cleanupAppInLaunchingProvidersLocked(app, true);
+ mService.mProcessList.removeProcessLocked(app, false, true,
+ ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "timeout publishing content providers");
+ }
+
+ List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
+ final List<ProviderInfo> providers;
+ try {
+ providers = AppGlobals.getPackageManager().queryContentProviders(
+ app.processName, app.uid, ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DIRECT_BOOT_AUTO, /*metaDataKey=*/ null)
+ .getList();
+ } catch (RemoteException ex) {
+ return null;
+ }
+ if (providers == null) {
+ return null;
+ }
+
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+ }
+
+ int numProviders = providers.size();
+ app.pubProviders.ensureCapacity(numProviders + app.pubProviders.size());
+ for (int i = 0; i < numProviders; i++) {
+ // NOTE: keep logic in sync with installEncryptionUnawareProviders
+ ProviderInfo cpi = providers.get(i);
+ boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo,
+ cpi.name, cpi.flags);
+ if (singleton && app.userId != UserHandle.USER_SYSTEM) {
+ // This is a singleton provider, but a user besides the
+ // default user is asking to initialize a process it runs
+ // in... well, no, it doesn't actually run in this process,
+ // it runs in the process of the default user. Get rid of it.
+ providers.remove(i);
+ numProviders--;
+ i--;
+ continue;
+ }
+
+ ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
+ ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, app.userId);
+ if (cpr == null) {
+ cpr = new ContentProviderRecord(mService, cpi, app.info, comp, singleton);
+ mProviderMap.putProviderByClass(comp, cpr);
+ }
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
+ }
+ app.pubProviders.put(cpi.name, cpr);
+ if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
+ // Don't add this if it is a platform component that is marked
+ // to run in multiple processes, because this is actually
+ // part of the framework so doesn't make sense to track as a
+ // separate apk in the process.
+ app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.longVersionCode,
+ mService.mProcessStats);
+ }
+ mService.notifyPackageUse(cpi.applicationInfo.packageName,
+ PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
+ }
+ return providers;
+ }
+
+ private final class DevelopmentSettingsObserver extends ContentObserver {
+ private final Uri mUri = Settings.Global.getUriFor(
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
+
+ private final ComponentName mBugreportStorageProvider = new ComponentName(
+ "com.android.shell", "com.android.shell.BugreportStorageProvider");
+
+ DevelopmentSettingsObserver() {
+ super(mService.mHandler);
+ mService.mContext.getContentResolver().registerContentObserver(mUri, false, this,
+ UserHandle.USER_ALL);
+ // Always kick once to ensure that we match current state
+ onChange();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
+ if (mUri.equals(uri)) {
+ onChange();
+ }
+ }
+
+ private void onChange() {
+ final boolean enabled = Settings.Global.getInt(mService.mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, Build.IS_ENG ? 1 : 0) != 0;
+ mService.mContext.getPackageManager().setComponentEnabledSetting(
+ mBugreportStorageProvider,
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ 0);
+ }
+ }
+
+ public final void installSystemProviders() {
+ List<ProviderInfo> providers;
+ synchronized (mService) {
+ ProcessRecord app = mService.mProcessList.mProcessNames.get("system", SYSTEM_UID);
+ providers = generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ ProviderInfo pi = providers.get(i);
+ if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Slog.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
+ }
+ }
+ }
+ if (providers != null) {
+ mService.mSystemThread.installSystemProviders(providers);
+ }
+
+ synchronized (mService) {
+ mSystemProvidersInstalled = true;
+ }
+ mService.mConstants.start(mService.mContext.getContentResolver());
+ mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
+ mService.mActivityTaskManager.installSystemProviders();
+ new DevelopmentSettingsObserver(); // init to observe developer settings enable/disable
+ SettingsToPropertiesMapper.start(mService.mContext.getContentResolver());
+ mService.mOomAdjuster.initSettings();
+
+ // Now that the settings provider is published we can consider sending in a rescue party.
+ RescueParty.onSettingsProviderPublished(mService.mContext);
+ }
+
+ /**
+ * When a user is unlocked, we need to install encryption-unaware providers
+ * belonging to any running apps.
+ */
+ void installEncryptionUnawareProviders(int userId) {
+ // We're only interested in providers that are encryption unaware, and
+ // we don't care about uninstalled apps, since there's no way they're
+ // running at this point.
+ final int matchFlags =
+ PackageManager.GET_PROVIDERS | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+ synchronized (mService) {
+ final int numProc = mService.mProcessList.mProcessNames.getMap().size();
+ for (int iProc = 0; iProc < numProc; iProc++) {
+ final SparseArray<ProcessRecord> apps =
+ mService.mProcessList.mProcessNames.getMap().valueAt(iProc);
+ for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) {
+ final ProcessRecord app = apps.valueAt(iApp);
+ if (app.userId != userId || app.thread == null || app.unlocked) continue;
+
+ for (int iPkg = 0, numPkgs = app.pkgList.size(); iPkg < numPkgs; iPkg++) {
+ try {
+ final String pkgName = app.pkgList.keyAt(iPkg);
+ final PackageInfo pkgInfo = AppGlobals.getPackageManager()
+ .getPackageInfo(pkgName, matchFlags, userId);
+ if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
+ for (ProviderInfo pi : pkgInfo.providers) {
+ // NOTE: keep in sync with generateApplicationProvidersLocked
+ final boolean processMatch =
+ Objects.equals(pi.processName, app.processName)
+ || pi.multiprocess;
+ final boolean userMatch = !mService.isSingleton(
+ pi.processName, pi.applicationInfo, pi.name, pi.flags)
+ || app.userId == UserHandle.USER_SYSTEM;
+ if (processMatch && userMatch) {
+ Log.v(TAG, "Installing " + pi);
+ app.thread.scheduleInstallProvider(pi);
+ } else {
+ Log.v(TAG, "Skipping " + pi);
+ }
+ }
+ }
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
+ final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
+ String callingPackage, String callingTag, boolean stable, boolean updateLru,
+ long startTime, ProcessList processList) {
+ if (r == null) {
+ cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+ return null;
+ }
+
+
+ for (int i = 0, size = r.conProviders.size(); i < size; i++) {
+ ContentProviderConnection conn = r.conProviders.get(i);
+ if (conn.provider == cpr) {
+ conn.incrementCount(stable);
+ return conn;
+ }
+ }
+
+ // Create a new ContentProviderConnection. The reference count is known to be 1.
+ ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage);
+ conn.startAssociationIfNeeded();
+ conn.initializeCount(stable);
+ cpr.connections.add(conn);
+ r.conProviders.add(conn);
+ mService.startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
+ cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ if (updateLru && cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+ // If this is a perceptible app accessing the provider, make
+ // sure to count it as being accessed and thus back up on
+ // the LRU list. This is good because content providers are
+ // often expensive to start. The calls to checkTime() use
+ // the "getContentProviderImpl" tag here, because it's part
+ // of the checktime log in getContentProviderImpl().
+ checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
+ processList.updateLruProcessLocked(cpr.proc, false, null);
+ checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
+ }
+ return conn;
+ }
+
+ @GuardedBy("mService")
+ private boolean decProviderCountLocked(ContentProviderConnection conn,
+ ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
+ if (conn == null) {
+ cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ return false;
+ }
+ if (conn.decrementCount(stable) != 0) {
+ return false;
+ }
+
+ cpr = conn.provider;
+ conn.stopAssociation();
+ cpr.connections.remove(conn);
+ conn.client.conProviders.remove(conn);
+ if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+ // The client is more important than last activity -- note the time this
+ // is happening, so we keep the old provider process around a bit as last
+ // activity to avoid thrashing it.
+ if (cpr.proc != null) {
+ cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
+ }
+ }
+ mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
+ cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ return true;
+ }
+
/**
* Check if {@link ProcessRecord} has a possible chance at accessing the
* given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
*/
- private String checkContentProviderPermissionLocked(
- ProviderInfo cpi, ProcessRecord r, int userId, boolean checkUser) {
+ private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r,
+ int userId, boolean checkUser) {
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
boolean checkedGrants = false;
@@ -345,7 +1288,7 @@
false, ActivityManagerInternal.ALLOW_NON_FULL,
"checkContentProviderPermissionLocked " + cpi.authority, null);
if (userId != tmpTargetUserId) {
- // When we actually went to determine the final targer user ID, this ended
+ // When we actually went to determine the final target user ID, this ended
// up different than our initial check for the authority. This is because
// they had asked for USER_CURRENT_OR_SELF and we ended up switching to
// SELF. So we need to re-check the grants again.
@@ -418,818 +1361,41 @@
return null;
}
- void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
- mService.enforceCallingPermission(
- android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
- "Do not have permission in call removeContentProviderExternal()");
- long ident = Binder.clearCallingIdentity();
- try {
- removeContentProviderExternalUnchecked(name, token, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- void removeContentProviderExternalUnchecked(String name, IBinder token, int userId) {
- synchronized (mService) {
- ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
- if (cpr == null) {
- //remove from mProvidersByClass
- if (ActivityManagerDebugConfig.DEBUG_ALL) {
- Slog.v(TAG, name + " content provider not found in providers list");
- }
- return;
- }
-
- // update content provider record entry info
- ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
- ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
- if (localCpr.hasExternalProcessHandles()) {
- if (localCpr.removeExternalProcessHandleLocked(token)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
- } else {
- Slog.e(TAG, "Attmpt to remove content provider " + localCpr
- + " with no external reference for token: "
- + token + ".");
- }
- } else {
- Slog.e(TAG, "Attmpt to remove content provider: " + localCpr
- + " with no external references.");
+ ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
+ ProviderInfo pi = null;
+ ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
+ if (cpr != null) {
+ pi = cpr.info;
+ } else {
+ try {
+ pi = AppGlobals.getPackageManager().resolveContentProvider(
+ authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
+ } catch (RemoteException ex) {
}
}
+ return pi;
}
- public boolean refContentProvider(IBinder connection, int stable, int unstable) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection) connection;
- } catch (ClassCastException e) {
- String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
-
- conn.adjustCounts(stable, unstable);
- return !conn.dead;
- }
-
- public void unstableProviderDied(IBinder connection) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection) connection;
- } catch (ClassCastException e) {
- String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
-
- // Safely retrieve the content provider associated with the connection.
- IContentProvider provider;
- synchronized (mService) {
- provider = conn.provider.provider;
- }
-
- if (provider == null) {
- // Um, yeah, we're way ahead of you.
+ private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
+ String authority) {
+ if (app == null
+ || app.getCurProcState() > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
return;
}
- // Make sure the caller is being honest with us.
- if (provider.asBinder().pingBinder()) {
- // Er, no, still looks good to us.
- synchronized (mService) {
- Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
- + " says " + conn + " died, but we don't agree");
- return;
+
+ UserState userState = mService.mUserController.getStartedUserState(app.userId);
+ if (userState == null) return;
+ final long now = SystemClock.elapsedRealtime();
+ Long lastReported = userState.mProviderLastReportedFg.get(authority);
+ if (lastReported == null || lastReported < now - 60 * 1000L) {
+ if (mService.mSystemReady) {
+ // Cannot touch the user stats if not system ready
+ mService.mUsageStatsService.reportContentProviderUsage(
+ authority, providerPkgName, app.userId);
}
+ userState.mProviderLastReportedFg.put(authority, now);
}
-
- // Well look at that! It's dead!
- synchronized (mService) {
- if (conn.provider.provider != provider) {
- // But something changed... good enough.
- return;
- }
-
- ProcessRecord proc = conn.provider.proc;
- if (proc == null || proc.thread == null) {
- // Seems like the process is already cleaned up.
- return;
- }
-
- // As far as we're concerned, this is just like receiving a
- // death notification... just a bit prematurely.
- mService.reportUidInfoMessageLocked(TAG,
- "Process " + proc.processName + " (pid " + proc.pid
- + ") early provider death",
- proc.info.uid);
- final long ident = Binder.clearCallingIdentity();
- try {
- mService.appDiedLocked(proc, "unstable content provider");
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- public void appNotRespondingViaProvider(IBinder connection) {
- mService.enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
- "appNotRespondingViaProvider()");
-
- final ContentProviderConnection conn = (ContentProviderConnection) connection;
- if (conn == null) {
- Slog.w(TAG, "ContentProviderConnection is null");
- return;
- }
-
- final ProcessRecord host = conn.provider.proc;
- if (host == null) {
- Slog.w(TAG, "Failed to find hosting ProcessRecord");
- return;
- }
-
- mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");
- }
-
- /**
- * Allows apps to retrieve the MIME type of a URI.
- * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
- * users, then it does not need permission to access the ContentProvider.
- * Either, it needs cross-user uri grants.
- *
- * CTS tests for this functionality can be run with "runtest cts-appsecurity".
- *
- * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
- * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
- *
- * @deprecated -- use getProviderMimeTypeAsync.
- */
- @Deprecated
- public String getProviderMimeType(Uri uri, int userId) {
- mService.enforceNotIsolatedCaller("getProviderMimeType");
- final String name = uri.getAuthority();
- int callingUid = Binder.getCallingUid();
- int callingPid = Binder.getCallingPid();
- long ident = 0;
- boolean clearedIdentity = false;
- userId = mService.mUserController.unsafeConvertIncomingUser(userId);
- if (canClearIdentity(callingPid, callingUid, userId)) {
- clearedIdentity = true;
- ident = Binder.clearCallingIdentity();
- }
- ContentProviderHolder holder = null;
- try {
- holder = getContentProviderExternalUnchecked(name, null, callingUid,
- "*getmimetype*", userId);
- if (holder != null) {
- final IBinder providerConnection = holder.connection;
- final ComponentName providerName = holder.info.getComponentName();
- // Note: creating a new Runnable instead of using a lambda here since lambdas in
- // java provide no guarantee that there will be a new instance returned every call.
- // Hence, it's possible that a cached copy is returned and the ANR is executed on
- // the incorrect provider.
- final Runnable providerNotResponding = new Runnable() {
- @Override
- public void run() {
- Log.w(TAG, "Provider " + providerName + " didn't return from getType().");
- appNotRespondingViaProvider(providerConnection);
- }
- };
- mService.mHandler.postDelayed(providerNotResponding, 1000);
- try {
- return holder.provider.getType(uri);
- } finally {
- mService.mHandler.removeCallbacks(providerNotResponding);
- }
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- return null;
- } catch (Exception e) {
- Log.w(TAG, "Exception while determining type of " + uri, e);
- return null;
- } finally {
- // We need to clear the identity to call removeContentProviderExternalUnchecked
- if (!clearedIdentity) {
- ident = Binder.clearCallingIdentity();
- }
- try {
- if (holder != null) {
- removeContentProviderExternalUnchecked(name, null, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- return null;
- }
-
- /**
- * Allows apps to retrieve the MIME type of a URI.
- * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
- * users, then it does not need permission to access the ContentProvider.
- * Either way, it needs cross-user uri grants.
- */
- public void getProviderMimeTypeAsync(Uri uri, int userId, RemoteCallback resultCallback) {
- mService.enforceNotIsolatedCaller("getProviderMimeTypeAsync");
- final String name = uri.getAuthority();
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
- final long ident = canClearIdentity(callingPid, callingUid, userId)
- ? Binder.clearCallingIdentity() : 0;
- try {
- final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
- callingUid, "*getmimetype*", safeUserId);
- if (holder != null) {
- holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
- final long identity = Binder.clearCallingIdentity();
- try {
- removeContentProviderExternalUnchecked(name, null, safeUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- resultCallback.sendResult(result);
- }));
- } else {
- resultCallback.sendResult(Bundle.EMPTY);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- resultCallback.sendResult(Bundle.EMPTY);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private boolean canClearIdentity(int callingPid, int callingUid, int userId) {
- if (UserHandle.getUserId(callingUid) == userId) {
- return true;
- }
- if (ActivityManagerService.checkComponentPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS, callingPid,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
- || ActivityManagerService.checkComponentPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPid,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- return false;
- }
-
- int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
- if (Thread.holdsLock(mService.mActivityTaskManager.getGlobalLock())) {
- Slog.wtf(TAG, new IllegalStateException("Unable to check Uri permission"
- + " because caller is holding WM lock; assuming permission denied"));
- return PackageManager.PERMISSION_DENIED;
- }
-
- final String name = uri.getAuthority();
- final long ident = Binder.clearCallingIdentity();
- ContentProviderHolder holder = null;
- try {
- holder = getContentProviderExternalUnchecked(name, null, callingUid,
- "*checkContentProviderUriPermission*", userId);
- if (holder != null) {
- return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- return PackageManager.PERMISSION_DENIED;
- } catch (Exception e) {
- Log.w(TAG, "Exception while determining type of " + uri, e);
- return PackageManager.PERMISSION_DENIED;
- } finally {
- try {
- if (holder != null) {
- removeContentProviderExternalUnchecked(name, null, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- return PackageManager.PERMISSION_DENIED;
- }
-
- /**
- * Drop a content provider from a ProcessRecord's bookkeeping
- */
- void removeContentProvider(IBinder connection, boolean stable) {
- mService.enforceNotIsolatedCaller("removeContentProvider");
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mService) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection) connection;
- } catch (ClassCastException e) {
- String msg = "removeContentProvider: " + connection
- + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
- if (decProviderCountLocked(conn, null, null, stable)) {
- mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- ContentProviderHolder getContentProvider(IApplicationThread caller, String callingPackage,
- String name, int userId, boolean stable) {
- mService.enforceNotIsolatedCaller("getContentProvider");
- if (caller == null) {
- String msg = "null IApplicationThread when getting content provider " + name;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
- // with cross-user grant.
- final int callingUid = Binder.getCallingUid();
- if (callingPackage != null && mService.mAppOpsService.checkPackage(
- callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
- throw new SecurityException("Given calling package " + callingPackage
- + " does not match caller's uid " + callingUid);
- }
- return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
- null, stable, userId);
- }
-
- private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token, int callingUid, String callingPackage, String callingTag,
- boolean stable, int userId) {
- ContentProviderRecord cpr;
- ContentProviderConnection conn = null;
- ProviderInfo cpi = null;
- boolean providerRunning = false;
- synchronized (mService) {
- long startTime = SystemClock.uptimeMillis();
-
- ProcessRecord r = null;
- if (caller != null) {
- r = mService.getRecordForAppLocked(caller);
- if (r == null) {
- throw new SecurityException("Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid() + ") when getting content provider "
- + name);
- }
- }
-
- boolean checkCrossUser = true;
-
- checkTime(startTime, "getContentProviderImpl: getProviderByName");
-
- // First check if this content provider has been published...
- cpr = mProviderMap.getProviderByName(name, userId);
- // If that didn't work, check if it exists for user 0 and then
- // verify that it's a singleton provider before using it.
- if (cpr == null && userId != UserHandle.USER_SYSTEM) {
- cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
- if (cpr != null) {
- cpi = cpr.info;
- if (mService.isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags)
- && mService.isValidSingletonCall(r == null ? callingUid : r.uid,
- cpi.applicationInfo.uid)) {
- userId = UserHandle.USER_SYSTEM;
- checkCrossUser = false;
- } else {
- cpr = null;
- cpi = null;
- }
- }
- }
-
- ProcessRecord dyingProc = null;
- if (cpr != null && cpr.proc != null) {
- providerRunning = !cpr.proc.killed;
-
- // Note if killedByAm is also set, this means the provider process has just been
- // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
- // yet. So we need to call appDiedLocked() here and let it clean up.
- // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
- // how to test this case.)
- if (cpr.proc.killed && cpr.proc.killedByAm) {
- Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
- // Now we are going to wait for the death before starting the new process.
- dyingProc = cpr.proc;
- }
- }
-
- if (providerRunning) {
- cpi = cpr.info;
- String msg;
-
- if (r != null && cpr.canRunHere(r)) {
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
-
- // This provider has been published or is in the process
- // of being published... but it is also allowed to run
- // in the caller's process, so don't make a connection
- // and just let the caller instantiate its own instance.
- ContentProviderHolder holder = cpr.newHolder(null);
- // don't give caller the provider object, it needs
- // to make its own.
- holder.provider = null;
- return holder; //what?
- }
-
- // Don't expose providers between normal apps and instant apps
- try {
- if (AppGlobals.getPackageManager()
- .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
- return null;
- }
- } catch (RemoteException e) {
- }
-
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
-
- final long origId = Binder.clearCallingIdentity();
-
- checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
-
- // In this case the provider instance already exists, so we can
- // return it right away.
- conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
- stable, true, startTime, mService.mProcessList);
-
- checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
- final int verifiedAdj = cpr.proc.verifiedAdj;
- boolean success = mService.updateOomAdjLocked(cpr.proc, true,
- OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- // XXX things have changed so updateOomAdjLocked doesn't actually tell us
- // if the process has been successfully adjusted. So to reduce races with
- // it, we will check whether the process still exists. Note that this doesn't
- // completely get rid of races with LMK killing the process, but should make
- // them much smaller.
- if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
- success = false;
- }
- maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
- checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
- if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
- Slog.i(TAG, "Adjust success: " + success);
- }
- // NOTE: there is still a race here where a signal could be
- // pending on the process even though we managed to update its
- // adj level. Not sure what to do about this, but at least
- // the race is now smaller.
- if (!success) {
- // Uh oh... it looks like the provider's process
- // has been killed on us. We need to wait for a new
- // process to be started, and make sure its death
- // doesn't kill our process.
- Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
- + " is crashing; detaching " + r);
- boolean lastRef = decProviderCountLocked(conn, cpr,
- token, stable);
- if (!lastRef) {
- // This wasn't the last ref our process had on
- // the provider... we will be killed during cleaning up, bail.
- return null;
- }
- // We'll just start a new process to host the content provider
- providerRunning = false;
- conn = null;
- dyingProc = cpr.proc;
- } else {
- cpr.proc.verifiedAdj = cpr.proc.setAdj;
- }
-
- Binder.restoreCallingIdentity(origId);
- }
-
- if (!providerRunning) {
- try {
- checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
- cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
- ActivityManagerService.STOCK_PM_FLAGS
- | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
- checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
- } catch (RemoteException ex) {
- }
- if (cpi == null) {
- return null;
- }
- // If the provider is a singleton AND
- // (it's a call within the same user || the provider is a
- // privileged app)
- // Then allow connecting to the singleton provider
- boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags)
- && mService.isValidSingletonCall(r == null ? callingUid : r.uid,
- cpi.applicationInfo.uid);
- if (singleton) {
- userId = UserHandle.USER_SYSTEM;
- }
- cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
- checkTime(startTime, "getContentProviderImpl: got app info for user");
-
- String msg;
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup " + name
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
-
- if (!mService.mProcessesReady
- && !cpi.processName.equals("system")) {
- // If this content provider does not run in the system
- // process, and the system is not yet ready to run other
- // processes, then fail fast instead of hanging.
- throw new IllegalArgumentException(
- "Attempt to launch content provider before system ready");
- }
-
- // If system providers are not installed yet we aggressively crash to avoid
- // creating multiple instance of these providers and then bad things happen!
- if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
- && "system".equals(cpi.processName)) {
- throw new IllegalStateException("Cannot access system provider: '"
- + cpi.authority + "' before system providers are installed!");
- }
-
- // Make sure that the user who owns this provider is running. If not,
- // we don't want to allow it to run.
- if (!mService.mUserController.isUserRunning(userId, 0)) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": user " + userId + " is stopped");
- return null;
- }
-
- ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
- checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
- cpr = mProviderMap.getProviderByClass(comp, userId);
- checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
- boolean firstClass = cpr == null;
- if (firstClass) {
- final long ident = Binder.clearCallingIdentity();
-
- // If permissions need a review before any of the app components can run,
- // we return no provider and launch a review activity if the calling app
- // is in the foreground.
- if (!requestTargetProviderPermissionsReviewIfNeededLocked(
- cpi, r, userId, mService.mContext)) {
- return null;
- }
-
- try {
- checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
- ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
- cpi.applicationInfo.packageName,
- ActivityManagerService.STOCK_PM_FLAGS, userId);
- checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
- if (ai == null) {
- Slog.w(TAG, "No package info for content provider " + cpi.name);
- return null;
- }
- ai = mService.getAppInfoForUser(ai, userId);
- cpr = new ContentProviderRecord(mService, cpi, ai, comp, singleton);
- } catch (RemoteException ex) {
- // pm is in same process, this will never happen.
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- } else if (dyingProc == cpr.proc && dyingProc != null) {
- // The old stable connection's client should be killed during proc cleaning up,
- // so do not re-use the old ContentProviderRecord, otherwise the new clients
- // could get killed unexpectedly.
- cpr = new ContentProviderRecord(cpr);
- // This is sort of "firstClass"
- firstClass = true;
- }
-
- checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
-
- if (r != null && cpr.canRunHere(r)) {
- // If this is a multiprocess provider, then just return its
- // info and allow the caller to instantiate it. Only do
- // this if the provider is the same user as the caller's
- // process, or can run as root (so can be in any process).
- return cpr.newHolder(null);
- }
-
- if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
- Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
- + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name
- + " callers=" + Debug.getCallers(6));
- }
-
- // This is single process, and our app is now connecting to it.
- // See if we are already in the process of launching this
- // provider.
- final int N = mLaunchingProviders.size();
- int i;
- for (i = 0; i < N; i++) {
- if (mLaunchingProviders.get(i) == cpr) {
- break;
- }
- }
-
- // If the provider is not already being launched, then get it
- // started.
- if (i >= N) {
- final long origId = Binder.clearCallingIdentity();
-
- try {
- // Content provider is now in use, its package can't be stopped.
- try {
- checkTime(startTime,
- "getContentProviderImpl: before set stopped state");
- AppGlobals.getPackageManager().setPackageStoppedState(
- cpr.appInfo.packageName, false, userId);
- checkTime(startTime, "getContentProviderImpl: after set stopped state");
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + cpr.appInfo.packageName + ": " + e);
- }
-
- // Use existing process if already started
- checkTime(startTime, "getContentProviderImpl: looking for process record");
- ProcessRecord proc = mService.getProcessRecordLocked(
- cpi.processName, cpr.appInfo.uid, false);
- if (proc != null && proc.thread != null && !proc.killed) {
- if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
- Slog.d(TAG, "Installing in existing process " + proc);
- }
- if (!proc.pubProviders.containsKey(cpi.name)) {
- checkTime(startTime, "getContentProviderImpl: scheduling install");
- proc.pubProviders.put(cpi.name, cpr);
- try {
- proc.thread.scheduleInstallProvider(cpi);
- } catch (RemoteException e) {
- }
- }
- } else {
- checkTime(startTime, "getContentProviderImpl: before start process");
- proc = mService.startProcessLocked(cpi.processName,
- cpr.appInfo, false, 0,
- new HostingRecord("content provider",
- new ComponentName(cpi.applicationInfo.packageName,
- cpi.name)),
- ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
- checkTime(startTime, "getContentProviderImpl: after start process");
- if (proc == null) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": process is bad");
- return null;
- }
- }
- cpr.launchingApp = proc;
- mLaunchingProviders.add(cpr);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- checkTime(startTime, "getContentProviderImpl: updating data structures");
-
- // Make sure the provider is published (the same provider class
- // may be published under multiple names).
- if (firstClass) {
- mProviderMap.putProviderByClass(comp, cpr);
- }
-
- mProviderMap.putProviderByName(name, cpr);
- conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
- stable, false, startTime, mService.mProcessList);
- if (conn != null) {
- conn.waiting = true;
- }
- }
- checkTime(startTime, "getContentProviderImpl: done!");
-
- mService.grantImplicitAccess(userId, null /*intent*/, callingUid,
- UserHandle.getAppId(cpi.applicationInfo.uid));
- }
-
- // Wait for the provider to be published...
- final long timeout =
- SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
- boolean timedOut = false;
- synchronized (cpr) {
- while (cpr.provider == null) {
- if (cpr.launchingApp == null) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": launching app became null");
- EventLogTags.writeAmProviderLostProcess(
- UserHandle.getUserId(cpi.applicationInfo.uid),
- cpi.applicationInfo.packageName,
- cpi.applicationInfo.uid, name);
- return null;
- }
- try {
- final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
- }
- if (conn != null) {
- conn.waiting = true;
- }
- cpr.wait(wait);
- if (cpr.provider == null) {
- timedOut = true;
- break;
- }
- } catch (InterruptedException ex) {
- } finally {
- if (conn != null) {
- conn.waiting = false;
- }
- }
- }
- }
- if (timedOut) {
- // Note we do it after releasing the lock.
- String callerName = "unknown";
- if (caller != null) {
- synchronized (mService) {
- final ProcessRecord record =
- mService.mProcessList.getLRURecordForAppLocked(caller);
- if (record != null) {
- callerName = record.processName;
- }
- }
- }
-
- Slog.wtf(TAG, "Timeout waiting for provider "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider " + name
- + " providerRunning=" + providerRunning
- + " caller=" + callerName + "/" + Binder.getCallingUid());
- return null;
- }
- return cpr.newHolder(conn);
- }
-
- ContentProviderHolder getContentProviderExternal(
- String name, int userId, IBinder token, String tag) {
- mService.enforceCallingPermission(
- android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
- "Do not have permission in call getContentProviderExternal()");
- userId = mService.mUserController.handleIncomingUser(
- Binder.getCallingPid(), Binder.getCallingUid(), userId,
- false, ActivityManagerInternal.ALLOW_FULL_ONLY, "getContentProvider", null);
- return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(),
- tag != null ? tag : "*external*", userId);
- }
-
- ContentProviderHolder getContentProviderExternalUnchecked(String name,
- IBinder token, int callingUid, String callingTag, int userId) {
- return getContentProviderImpl(null, name, token, callingUid, null, callingTag,
- true, userId);
}
private static final int[] PROCESS_STATE_STATS_FORMAT = new int[] {
@@ -1251,7 +1417,7 @@
proc.procStatFile = "/proc/" + proc.pid + "/stat";
}
mProcessStateStatsLongs[0] = 0;
- if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+ if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
mProcessStateStatsLongs, null)) {
if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
Slog.d(ActivityManagerService.TAG,
@@ -1270,220 +1436,53 @@
return false;
}
- public final void publishContentProviders(IApplicationThread caller,
- List<ContentProviderHolder> providers) {
- if (providers == null) {
- return;
- }
+ private static final class StartActivityRunnable implements Runnable {
+ private final Context mContext;
+ private final Intent mIntent;
+ private final UserHandle mUserHandle;
- mService.enforceNotIsolatedCaller("publishContentProviders");
- synchronized (mService) {
- final ProcessRecord r = mService.getRecordForAppLocked(caller);
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
- }
- if (r == null) {
- throw new SecurityException("Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when publishing content providers");
- }
-
- final long origId = Binder.clearCallingIdentity();
-
- final int N = providers.size();
- for (int i = 0; i < N; i++) {
- ContentProviderHolder src = providers.get(i);
- if (src == null || src.info == null || src.provider == null) {
- continue;
- }
- ContentProviderRecord dst = r.pubProviders.get(src.info.name);
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
- }
- if (dst != null) {
- ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
- mProviderMap.putProviderByClass(comp, dst);
- String[] names = dst.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- mProviderMap.putProviderByName(names[j], dst);
- }
-
- int launchingCount = mLaunchingProviders.size();
- int j;
- boolean wasInLaunchingProviders = false;
- for (j = 0; j < launchingCount; j++) {
- if (mLaunchingProviders.get(j) == dst) {
- mLaunchingProviders.remove(j);
- wasInLaunchingProviders = true;
- j--;
- launchingCount--;
- }
- }
- if (wasInLaunchingProviders) {
- mService.mHandler.removeMessages(
- ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
- }
- // Make sure the package is associated with the process.
- // XXX We shouldn't need to do this, since we have added the package
- // when we generated the providers in generateApplicationProvidersLocked().
- // But for some reason in some cases we get here with the package no longer
- // added... for now just patch it in to make things happy.
- r.addPackage(dst.info.applicationInfo.packageName,
- dst.info.applicationInfo.longVersionCode, mService.mProcessStats);
- synchronized (dst) {
- dst.provider = src.provider;
- dst.setProcess(r);
- dst.notifyAll();
- }
- dst.mRestartCount = 0;
- mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
- src.info.authority);
- }
- }
-
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
- String authority) {
- if (app == null) return;
- if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- UserState userState = mService.mUserController.getStartedUserState(app.userId);
- if (userState == null) return;
- final long now = SystemClock.elapsedRealtime();
- Long lastReported = userState.mProviderLastReportedFg.get(authority);
- if (lastReported == null || lastReported < now - 60 * 1000L) {
- if (mService.mSystemReady) {
- // Cannot touch the user stats if not system ready
- mService.mUsageStatsService.reportContentProviderUsage(
- authority, providerPkgName, app.userId);
- }
- userState.mProviderLastReportedFg.put(authority, now);
- }
- }
- }
-
- private final class DevelopmentSettingsObserver extends ContentObserver {
- private final Uri mUri = Settings.Global.getUriFor(
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
-
- private final ComponentName mBugreportStorageProvider = new ComponentName(
- "com.android.shell", "com.android.shell.BugreportStorageProvider");
-
- DevelopmentSettingsObserver() {
- super(mService.mHandler);
- mService.mContext.getContentResolver().registerContentObserver(mUri, false, this,
- UserHandle.USER_ALL);
- // Always kick once to ensure that we match current state
- onChange();
+ StartActivityRunnable(Context context, Intent intent, UserHandle userHandle) {
+ this.mContext = context;
+ this.mIntent = intent;
+ this.mUserHandle = userHandle;
}
@Override
- public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
- if (mUri.equals(uri)) {
- onChange();
- }
- }
-
- private void onChange() {
- final boolean enabled = Settings.Global.getInt(mService.mContext.getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, Build.IS_ENG ? 1 : 0) != 0;
- mService.mContext.getPackageManager().setComponentEnabledSetting(
- mBugreportStorageProvider,
- enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- 0);
+ public void run() {
+ mContext.startActivityAsUser(mIntent, mUserHandle);
}
}
- public final void installSystemProviders() {
- List<ProviderInfo> providers;
- synchronized (mService) {
- ProcessRecord app = mService.mProcessList.mProcessNames.get("system", SYSTEM_UID);
- providers = generateApplicationProvidersLocked(app);
- if (providers != null) {
- for (int i = providers.size() - 1; i >= 0; i--) {
- ProviderInfo pi = providers.get(i);
- if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- Slog.w(TAG, "Not installing system proc provider " + pi.name
- + ": not system .apk");
- providers.remove(i);
- }
- }
- }
- }
- if (providers != null) {
- mService.mSystemThread.installSystemProviders(providers);
+ private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
+ ProcessRecord r, final int userId, Context context) {
+ if (!mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ cpi.packageName, userId)) {
+ return true;
}
- synchronized (mService) {
- mSystemProvidersInstalled = true;
+ final boolean callerForeground = r == null
+ || r.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
+
+ // Show a permission review UI only for starting from a foreground app
+ if (!callerForeground) {
+ Slog.w(TAG, "u" + userId + " Instantiating a provider in package "
+ + cpi.packageName + " requires a permissions review");
+ return false;
}
- mService.mConstants.start(mService.mContext.getContentResolver());
- mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
- mService.mActivityTaskManager.installSystemProviders();
- new DevelopmentSettingsObserver(); // init to observe developer settings enable/disable
- SettingsToPropertiesMapper.start(mService.mContext.getContentResolver());
- mService.mOomAdjuster.initSettings();
- // Now that the settings provider is published we can consider sending
- // in a rescue party.
- RescueParty.onSettingsProviderPublished(mService.mContext);
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
- //mUsageStatsService.monitorPackages();
- }
-
- /**
- * When a user is unlocked, we need to install encryption-unaware providers
- * belonging to any running apps.
- */
- void installEncryptionUnawareProviders(int userId) {
- // We're only interested in providers that are encryption unaware, and
- // we don't care about uninstalled apps, since there's no way they're
- // running at this point.
- final int matchFlags =
- PackageManager.GET_PROVIDERS | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-
- synchronized (mService) {
- final int NP = mService.mProcessList.mProcessNames.getMap().size();
- for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps =
- mService.mProcessList.mProcessNames.getMap().valueAt(ip);
- final int NA = apps.size();
- for (int ia = 0; ia < NA; ia++) {
- final ProcessRecord app = apps.valueAt(ia);
- if (app.userId != userId || app.thread == null || app.unlocked) continue;
-
- final int NG = app.pkgList.size();
- for (int ig = 0; ig < NG; ig++) {
- try {
- final String pkgName = app.pkgList.keyAt(ig);
- final PackageInfo pkgInfo = AppGlobals.getPackageManager()
- .getPackageInfo(pkgName, matchFlags, userId);
- if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
- for (ProviderInfo pi : pkgInfo.providers) {
- // TODO: keep in sync with generateApplicationProvidersLocked
- final boolean processMatch = Objects.equals(pi.processName,
- app.processName) || pi.multiprocess;
- final boolean userMatch = mService.isSingleton(pi.processName,
- pi.applicationInfo, pi.name, pi.flags)
- ? (app.userId == UserHandle.USER_SYSTEM) : true;
- if (processMatch && userMatch) {
- Log.v(TAG, "Installing " + pi);
- app.thread.scheduleInstallProvider(pi);
- } else {
- Log.v(TAG, "Skipping " + pi);
- }
- }
- }
- } catch (RemoteException ignored) {
- }
- }
- }
- }
+ if (ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + userId + " Launching permission review "
+ + "for package " + cpi.packageName);
}
+
+ final UserHandle userHandle = new UserHandle(userId);
+ mService.mHandler.post(new StartActivityRunnable(context, intent, userHandle));
+
+ return false;
}
/**
@@ -1493,8 +1492,8 @@
* @param always If true, remove the provider from launching map always, no more restart attempt
* @return true if the given provider is in launching
*/
- boolean removeDyingProviderLocked(ProcessRecord proc,
- ContentProviderRecord cpr, boolean always) {
+ boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr,
+ boolean always) {
boolean inLaunching = mLaunchingProviders.contains(cpr);
if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
// It's being launched but we've reached maximum attempts, force the removal
@@ -1536,10 +1535,8 @@
conn.dead = true;
if (conn.stableCount() > 0) {
if (!capp.isPersistent() && capp.thread != null
- && capp.pid != 0
- && capp.pid != ActivityManagerService.MY_PID) {
- capp.kill("depends on provider "
- + cpr.name.flattenToShortString()
+ && capp.pid != 0 && capp.pid != ActivityManagerService.MY_PID) {
+ capp.kill("depends on provider " + cpr.name.flattenToShortString()
+ " in dying proc " + (proc != null ? proc.processName : "??")
+ " (adj " + (proc != null ? proc.setAdj : "??") + ")",
ApplicationExitInfo.REASON_DEPENDENCY_DIED,
@@ -1555,8 +1552,8 @@
// clean up this connection, we'll just remove it.
cpr.connections.remove(i);
if (conn.client.conProviders.remove(conn)) {
- mService.stopAssociationLocked(capp.uid, capp.processName, cpr.uid,
- cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ mService.stopAssociationLocked(capp.uid, capp.processName,
+ cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
}
}
}
@@ -1587,22 +1584,24 @@
boolean restart = false;
for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = mLaunchingProviders.get(i);
- if (cpr.launchingApp == app) {
- if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
- // It's being launched but we've reached maximum attempts, mark it as bad
- alwaysBad = true;
- }
- if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
- restart = true;
- } else {
- removeDyingProviderLocked(app, cpr, true);
- }
+ if (cpr.launchingApp != app) {
+ continue;
+ }
+
+ if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
+ // It's being launched but we've reached maximum attempts, mark it as bad
+ alwaysBad = true;
+ }
+ if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
+ restart = true;
+ } else {
+ removeDyingProviderLocked(app, cpr, true);
}
}
return restart;
}
- void cleanupLaunchingProviders() {
+ void cleanupLaunchingProvidersLocked() {
for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = mLaunchingProviders.get(i);
if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
@@ -1614,31 +1613,6 @@
}
}
- ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId,
- int pmFlags) {
- ProviderInfo pi = null;
- ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
- if (cpr != null) {
- pi = cpr.info;
- } else {
- try {
- pi = AppGlobals.getPackageManager().resolveContentProvider(
- authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
- } catch (RemoteException ex) {
- }
- }
- return pi;
- }
-
- @GuardedBy("mService")
- void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
- cleanupAppInLaunchingProvidersLocked(app, true);
- mService.mProcessList.removeProcessLocked(app, false, true,
- ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- "timeout publishing content providers");
- }
-
private void checkTime(long startTime, String where) {
long now = SystemClock.uptimeMillis();
if ((now - startTime) > 50) {
@@ -1649,16 +1623,13 @@
void dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
- boolean needSep;
- boolean printedAnything = false;
-
ActivityManagerService.ItemMatcher matcher = new ActivityManagerService.ItemMatcher();
matcher.build(args, opti);
pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
- needSep = mProviderMap.dumpProvidersLocked(pw, dumpAll, dumpPackage);
- printedAnything |= needSep;
+ boolean needSep = mProviderMap.dumpProvidersLocked(pw, dumpAll, dumpPackage);
+ boolean printedAnything = needSep;
if (mLaunchingProviders.size() > 0) {
boolean printed = false;
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index ca61788..8970ec4 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -92,7 +92,7 @@
sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
sGlobalSettingToTypeMap.put(
- Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST, String.class);
sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
@@ -105,9 +105,9 @@
sGlobalSettingToTypeMap.put(
Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_DENYLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_ALLOWLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_DENYLISTS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
// add other global settings here...
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0658e81..19b671e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -23,10 +23,11 @@
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1909,11 +1910,12 @@
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
- } else if (allowMode == ALLOW_NON_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
- } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
- || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE_OR_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup;
@@ -1940,12 +1942,15 @@
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
- if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
+ if (allowMode == ALLOW_NON_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL
+ || isSameProfileGroup) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
if (isSameProfileGroup
- && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ && (allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL)) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_PROFILES);
}
@@ -1972,7 +1977,8 @@
private boolean canInteractWithAcrossProfilesPermission(
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
String callingPackage) {
- if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ if (allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
+ && allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
return false;
}
if (!isSameProfileGroup) {
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 7e63e72..5db6dc7 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -45,6 +45,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.am.PersistentConnection;
import com.android.server.appbinding.finders.AppServiceFinder;
import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder;
@@ -125,18 +126,18 @@
}
@Override
- public void onStartUser(int userHandle) {
- mService.onStartUser(userHandle);
+ public void onUserStarting(@NonNull TargetUser user) {
+ mService.onStartUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userId) {
- mService.onUnlockUser(userId);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mService.onStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.onStopUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index e6480fc..74f3daf 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
@@ -128,6 +129,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -161,6 +163,7 @@
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
+import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2197,8 +2200,11 @@
+ " by uid " + Binder.getCallingUid());
}
+ int userId = UserHandle.getUserId(uid);
+
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
+ verifyIncomingUser(userId);
code = AppOpsManager.opToSwitch(code);
if (permissionPolicyCallback == null) {
@@ -2443,8 +2449,12 @@
private void setMode(int code, int uid, @NonNull String packageName, int mode,
@Nullable IAppOpsCallback permissionPolicyCallback) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -2857,8 +2867,11 @@
private int checkOperationImpl(int code, int uid, String packageName,
boolean raw) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -2977,10 +2990,15 @@
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
+ int proxiedUserId = UserHandle.getUserId(proxiedUid);
+ int proxyUserId = UserHandle.getUserId(proxyUid);
+
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
- verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
- verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
+ verifyIncomingUser(proxiedUserId);
+ verifyIncomingUser(proxyUserId);
+ verifyIncomingPackage(proxiedPackageName, proxiedUserId);
+ verifyIncomingPackage(proxyPackageName, proxyUserId);
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
if (resolveProxyPackageName == null) {
@@ -3030,9 +3048,12 @@
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3409,9 +3430,12 @@
public int startOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3491,9 +3515,12 @@
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3722,6 +3749,33 @@
}
}
+ private void verifyIncomingUser(@UserIdInt int userId) {
+ int callingUid = Binder.getCallingUid();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ int callingPid = Binder.getCallingPid();
+
+ if (callingUserId != userId) {
+ // Prevent endless loop between when checking appops inside of handleIncomingUser
+ if (Binder.getCallingPid() == ActivityManagerService.MY_PID) {
+ return;
+ }
+ long token = Binder.clearCallingIdentity();
+ try {
+ try {
+ LocalServices.getService(ActivityManagerInternal.class).handleIncomingUser(
+ callingPid, callingUid, userId, /* allowAll */ false,
+ ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL, "appop operation", null);
+ } catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "153996875", "appop", userId);
+
+ throw e;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
@@ -5801,8 +5855,11 @@
return false;
}
}
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
final String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 84de25c..a3e1b7a 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -7,6 +7,9 @@
"name": "CtsAppOps2TestCases"
},
{
+ "name": "CtsAppOpHostTestCases"
+ },
+ {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7051e4a..e128d99 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -108,7 +108,8 @@
private final PowerManager mPowerManager;
private final Object mLock;
@GuardedBy("mLock")
- private IAttentionService mService;
+ @VisibleForTesting
+ protected IAttentionService mService;
@GuardedBy("mLock")
private AttentionCheckCacheBuffer mAttentionCheckCacheBuffer;
@GuardedBy("mLock")
@@ -158,7 +159,8 @@
}
/** Resolves and sets up the attention service if it had not been done yet. */
- private boolean isServiceAvailable() {
+ @VisibleForTesting
+ protected boolean isServiceAvailable() {
if (mComponentName == null) {
mComponentName = resolveAttentionService(mContext);
}
@@ -168,12 +170,12 @@
/**
* Returns {@code true} if attention service is supported on this device.
*/
- private boolean isAttentionServiceSupported() {
+ @VisibleForTesting
+ protected boolean isAttentionServiceSupported() {
return isServiceEnabled() && isServiceConfigured(mContext);
}
- @VisibleForTesting
- protected boolean isServiceEnabled() {
+ private boolean isServiceEnabled() {
return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_SERVICE_ENABLED,
DEFAULT_SERVICE_ENABLED);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 2d77d6f..32be03f 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5855,11 +5855,13 @@
caller);
}
// fire changed intents for all streams
- mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
- mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
- mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
- mStreamVolumeAlias[mStreamType]);
- sendBroadcastToAll(mVolumeChanged);
+ if (index != oldIndex) {
+ mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+ mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
+ mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
+ mStreamVolumeAlias[mStreamType]);
+ sendBroadcastToAll(mVolumeChanged);
+ }
}
return changed;
}
@@ -7497,6 +7499,7 @@
pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
+ pw.print(" mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices));
pw.print(" mExtVolumeController="); pw.println(mExtVolumeController);
pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index b4c41b2..5e8f1ef 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -632,21 +632,28 @@
return result;
}
+ // Return `(null)` if given BluetoothDevice is null. Otherwise, return the anonymized address.
+ private String getAnonymizedAddress(BluetoothDevice btDevice) {
+ return btDevice == null ? "(null)" : btDevice.getAnonymizedAddress();
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
private void setBtScoActiveDevice(BluetoothDevice btDevice) {
- Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
+ Log.i(TAG, "setBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
+ + " -> " + getAnonymizedAddress(btDevice));
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
if (Objects.equals(btDevice, previousActiveDevice)) {
return;
}
if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
- + previousActiveDevice);
+ + getAnonymizedAddress(previousActiveDevice));
}
if (!handleBtScoActiveDeviceChange(btDevice, true)) {
- Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
+ Log.e(TAG, "setBtScoActiveDevice() failed to add new device "
+ + getAnonymizedAddress(btDevice));
// set mBluetoothHeadsetDevice to null when failing to add new device
btDevice = null;
}
@@ -826,7 +833,8 @@
mBluetoothHeadsetDevice, mScoAudioMode)) {
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
} else {
- Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
+ Log.w(TAG, "requestScoState: connect to "
+ + getAnonymizedAddress(mBluetoothHeadsetDevice)
+ " failed, mScoAudioMode=" + mScoAudioMode);
broadcastScoConnectionState(
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 0aeb7ab..4f37dcc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -194,19 +194,19 @@
return;
}
+ if (clientMonitor != mCurrentOperation.clientMonitor) {
+ Slog.e(getTag(), "[Ignoring Finish] " + clientMonitor + " does not match"
+ + " current: " + mCurrentOperation.clientMonitor);
+ return;
+ }
+
+ Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
mCurrentOperation.state = Operation.STATE_FINISHED;
if (mCurrentOperation.clientFinishCallback != null) {
mCurrentOperation.clientFinishCallback.onClientFinished(clientMonitor, success);
}
- if (clientMonitor != mCurrentOperation.clientMonitor) {
- throw new IllegalStateException("Mismatched operation, "
- + " current: " + mCurrentOperation.clientMonitor
- + " received: " + clientMonitor);
- }
-
- Slog.d(getTag(), "[Finished] " + clientMonitor + ", success: " + success);
if (mGestureAvailabilityDispatcher != null) {
mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.clientMonitor.getSensorId(), false /* active */);
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 61c99b8..88867fc 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -15,6 +15,8 @@
*/
package com.android.server.camera;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -43,6 +45,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.wm.WindowManagerInternal;
import java.util.ArrayList;
@@ -252,20 +255,20 @@
}
@Override
- public void onStartUser(int userHandle) {
+ public void onUserStarting(@NonNull TargetUser user) {
synchronized(mLock) {
if (mEnabledCameraUsers == null) {
// Initialize cameraserver, or update cameraserver if we are recovering
// from a crash.
- switchUserLocked(userHandle);
+ switchUserLocked(user.getUserIdentifier());
}
}
}
@Override
- public void onSwitchUser(int userHandle) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
synchronized(mLock) {
- switchUserLocked(userHandle);
+ switchUserLocked(to.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index ed3a223..a0bc7d8 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
@@ -59,6 +60,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -218,9 +220,9 @@
}
@Override
- public void onCleanupUser(int userId) {
+ public void onUserStopped(@NonNull TargetUser user) {
synchronized (mClipboards) {
- mClipboards.remove(userId);
+ mClipboards.remove(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a..7202f0f 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -21,14 +21,23 @@
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NETWORK;
+import static android.net.INetd.PERMISSION_NONE;
+import static android.net.INetd.PERMISSION_SYSTEM;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
+import static com.android.internal.util.ArrayUtils.convertToIntArray;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -51,7 +60,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
@@ -65,7 +73,6 @@
import java.util.Map.Entry;
import java.util.Set;
-
/**
* A utility class to inform Netd of UID permisisons.
* Does a mass update at boot and then monitors for app install/remove.
@@ -114,6 +121,13 @@
public int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
+
+ /**
+ * Check whether given uid has specific permission.
+ */
+ public int uidPermission(@NonNull final String permission, final int uid) {
+ return ActivityManager.checkUidPermission(permission, uid);
+ }
}
public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
@@ -156,8 +170,9 @@
}
mAllApps.add(UserHandle.getAppId(uid));
- boolean isNetwork = hasNetworkPermission(app);
- boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
+ final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
+ final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
+ || isCarryoverPackage(app.applicationInfo);
if (isNetwork || hasRestrictedPermission) {
Boolean permission = mApps.get(uid);
@@ -169,8 +184,7 @@
}
//TODO: unify the management of the permissions into one codepath.
- int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
+ final int otherNetdPerms = getNetdPermissionMask(uid);
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
@@ -186,13 +200,12 @@
for (int i = 0; i < systemPermission.size(); i++) {
ArraySet<String> perms = systemPermission.valueAt(i);
int uid = systemPermission.keyAt(i);
- int netdPermission = 0;
+ int netdPermission = PERMISSION_NONE;
// Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
if (perms != null) {
netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
- ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
- netdPermission |= perms.contains(INTERNET)
- ? INetd.PERMISSION_INTERNET : 0;
+ ? PERMISSION_UPDATE_DEVICE_STATS : 0;
+ netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0;
}
netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
@@ -207,48 +220,34 @@
}
@VisibleForTesting
- boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
- if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
- return false;
- }
- final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
- if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
- return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
+ boolean hasPermission(@NonNull final String permission, final int uid) {
+ return mDeps.uidPermission(permission, uid) == PackageManager.PERMISSION_GRANTED;
}
@VisibleForTesting
- boolean hasNetworkPermission(@NonNull final PackageInfo app) {
- return hasPermission(app, CHANGE_NETWORK_STATE);
+ // TODO : remove this check in the future(b/162295056). All apps should just request the
+ // appropriate permission for their use case since android Q.
+ boolean isCarryoverPackage(@Nullable final ApplicationInfo appInfo) {
+ if (appInfo == null) return false;
+ return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
+ // Backward compatibility for b/114245686, on devices that launched before Q daemons
+ // and apps running as the system UID are exempted from this check.
+ || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
}
@VisibleForTesting
- boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
- // TODO : remove this check in the future(b/31479477). All apps should just
- // request the appropriate permission for their use case since android Q.
- if (app.applicationInfo != null) {
- // Backward compatibility for b/114245686, on devices that launched before Q daemons
- // and apps running as the system UID are exempted from this check.
- if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
- return true;
- }
-
- if (app.applicationInfo.targetSdkVersion < VERSION_Q
- && isVendorApp(app.applicationInfo)) {
- return true;
- }
- }
-
- return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
- || hasPermission(app, NETWORK_STACK)
- || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ boolean hasRestrictedNetworkPermission(final int uid) {
+ return hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, uid)
+ || hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, uid)
+ || hasPermission(NETWORK_STACK, uid);
}
/** Returns whether the given uid has using background network permission. */
public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
// Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
// CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
- // networks. mApps contains the result of checks for both hasNetworkPermission and
- // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
+ // networks. mApps contains the result of checks for both CHANGE_NETWORK_STATE permission
+ // and hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
// permissions at least.
return mApps.containsKey(uid);
}
@@ -273,11 +272,11 @@
}
try {
if (add) {
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
+ mNetd.networkSetPermissionForUser(PERMISSION_NETWORK, convertToIntArray(network));
+ mNetd.networkSetPermissionForUser(PERMISSION_SYSTEM, convertToIntArray(system));
} else {
- mNetd.networkClearPermissionForUser(toIntArray(network));
- mNetd.networkClearPermissionForUser(toIntArray(system));
+ mNetd.networkClearPermissionForUser(convertToIntArray(network));
+ mNetd.networkClearPermissionForUser(convertToIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -323,14 +322,15 @@
}
@VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
+ protected Boolean highestPermissionForUid(Boolean currentPermission, String name, int uid) {
if (currentPermission == SYSTEM) {
return currentPermission;
}
try {
final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
- final boolean isNetwork = hasNetworkPermission(app);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
+ final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
+ final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(uid)
+ || isCarryoverPackage(app.applicationInfo);
if (isNetwork || hasRestrictedPermission) {
currentPermission = hasRestrictedPermission;
}
@@ -342,23 +342,14 @@
}
private int getPermissionForUid(final int uid) {
- int permission = INetd.PERMISSION_NONE;
// Check all the packages for this UID. The UID has the permission if any of the
// packages in it has the permission.
final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (String name : packages) {
- final PackageInfo app = getPackageInfo(name);
- if (app != null && app.requestedPermissions != null) {
- permission |= getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
- }
- }
- } else {
+ if (packages == null || packages.length <= 0) {
// The last package of this uid is removed from device. Clean the package up.
- permission = INetd.PERMISSION_UNINSTALLED;
+ return PERMISSION_UNINSTALLED;
}
- return permission;
+ return getNetdPermissionMask(uid);
}
/**
@@ -375,7 +366,7 @@
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
+ final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName, uid);
if (permission != mApps.get(uid)) {
mApps.put(uid, permission);
@@ -431,7 +422,7 @@
String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
for (String name : packages) {
- permission = highestPermissionForUid(permission, name);
+ permission = highestPermissionForUid(permission, name, uid);
if (permission == SYSTEM) {
// An app with this UID still has the SYSTEM permission.
// Therefore, this UID must already have the SYSTEM permission.
@@ -467,19 +458,13 @@
sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
}
- private static int getNetdPermissionMask(String[] requestedPermissions,
- int[] requestedPermissionsFlags) {
- int permissions = 0;
- if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
- for (int i = 0; i < requestedPermissions.length; i++) {
- if (requestedPermissions[i].equals(INTERNET)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_INTERNET;
- }
- if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
- }
+ private int getNetdPermissionMask(final int uid) {
+ int permissions = PERMISSION_NONE;
+ if (hasPermission(INTERNET, uid)) {
+ permissions |= PERMISSION_INTERNET;
+ }
+ if (hasPermission(UPDATE_DEVICE_STATS, uid)) {
+ permissions |= PERMISSION_UPDATE_DEVICE_STATS;
}
return permissions;
}
@@ -648,19 +633,19 @@
for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
int permissions = netdPermissionsAppIds.valueAt(i);
switch(permissions) {
- case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS):
allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_INTERNET:
+ case PERMISSION_INTERNET:
internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ case PERMISSION_UPDATE_DEVICE_STATS:
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_NONE:
+ case PERMISSION_NONE:
noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_UNINSTALLED:
+ case PERMISSION_UNINSTALLED:
uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
default:
Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
@@ -671,24 +656,24 @@
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(allPermissionAppIds));
+ PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
+ convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
- ArrayUtils.convertToIntArray(internetPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_INTERNET,
+ convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS,
+ convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
- ArrayUtils.convertToIntArray(noPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_NONE,
+ convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
- ArrayUtils.convertToIntArray(uninstalledAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_UNINSTALLED,
+ convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 9a910bf..1294e90 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@
import android.Manifest;
import android.accounts.Account;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
@@ -75,6 +76,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.FileDescriptor;
@@ -124,26 +126,25 @@
mService.onBootPhase(phase);
}
-
@Override
- public void onStartUser(int userHandle) {
- mService.onStartUser(userHandle);
+ public void onUserStarting(@NonNull TargetUser user) {
+ mService.onStartUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userHandle) {
- mService.onUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mService.onStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.onStopUser(user.getUserIdentifier());
}
@Override
- public void onCleanupUser(int userHandle) {
+ public void onUserStopped(@NonNull TargetUser user) {
synchronized (mService.mCache) {
- mService.mCache.remove(userHandle);
+ mService.mCache.remove(user.getUserIdentifier());
}
}
}
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index ec2b0c0..ad3cd67 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -491,7 +491,14 @@
mIsWideColor = SurfaceControl.getActiveColorMode(token)
== Display.COLOR_MODE_DISPLAY_P3;
- SurfaceControl.screenshot(token, s);
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ mDisplayManagerInternal.systemScreenshot(mDisplayId);
+ s.attachAndQueueBufferWithColorSpace(screenshotBuffer.getHardwareBuffer(),
+ screenshotBuffer.getColorSpace());
+
+ if (screenshotBuffer.containsSecureLayers()) {
+ mTransaction.setSecure(mSurfaceControl, true).apply();
+ }
st.updateTexImage();
st.getTransformMatrix(mTexMatrix);
} finally {
@@ -586,7 +593,6 @@
}
if (mSurfaceControl == null) {
- Transaction t = new Transaction();
try {
final SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession)
.setName("ColorFade")
@@ -602,15 +608,16 @@
return false;
}
- t.setLayerStack(mSurfaceControl, mDisplayLayerStack);
- t.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ mTransaction.setLayerStack(mSurfaceControl, mDisplayLayerStack);
+ mTransaction.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+ mDisplayId, mSurfaceControl);
+ mSurfaceLayout.onDisplayTransaction(mTransaction);
+ mTransaction.apply();
+
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
- mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
- mDisplayId, mSurfaceControl);
- mSurfaceLayout.onDisplayTransaction(t);
- t.apply();
}
return true;
}
@@ -652,7 +659,7 @@
if (mSurfaceControl != null) {
mSurfaceLayout.dispose();
mSurfaceLayout = null;
- new Transaction().remove(mSurfaceControl).apply();
+ mTransaction.remove(mSurfaceControl).apply();
mSurface.release();
mSurfaceControl = null;
mSurfaceVisible = false;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a00c22a..0979ad6 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -104,6 +104,7 @@
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.UiThread;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
@@ -417,7 +418,8 @@
}
@Override
- public void onSwitchUser(@UserIdInt int newUserId) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ final int newUserId = to.getUserIdentifier();
final int userSerial = getUserManager().getUserSerialNumber(newUserId);
synchronized (mSyncRoot) {
if (mCurrentUserId != newUserId) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 95a98f1..92a3ccf 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -58,6 +58,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Secure;
@@ -76,6 +77,7 @@
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -205,30 +207,24 @@
}
@Override
- public void onStartUser(int userHandle) {
- super.onStartUser(userHandle);
-
+ public void onUserStarting(@NonNull TargetUser user) {
if (mCurrentUser == UserHandle.USER_NULL) {
final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
- message.arg1 = userHandle;
+ message.arg1 = user.getUserIdentifier();
mHandler.sendMessage(message);
}
}
@Override
- public void onSwitchUser(int userHandle) {
- super.onSwitchUser(userHandle);
-
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
- message.arg1 = userHandle;
+ message.arg1 = to.getUserIdentifier();
mHandler.sendMessage(message);
}
@Override
- public void onStopUser(int userHandle) {
- super.onStopUser(userHandle);
-
- if (mCurrentUser == userHandle) {
+ public void onUserStopping(@NonNull TargetUser user) {
+ if (mCurrentUser == user.getUserIdentifier()) {
final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
message.arg1 = UserHandle.USER_NULL;
mHandler.sendMessage(message);
@@ -819,7 +815,13 @@
return LocalDateTime.MIN;
}
- private boolean setAppSaturationLevelInternal(String callingPackageName,
+ void setSaturationLevelInternal(int saturationLevel) {
+ final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
+ message.arg1 = saturationLevel;
+ mHandler.sendMessage(message);
+ }
+
+ boolean setAppSaturationLevelInternal(String callingPackageName,
String affectedPackageName, int saturationLevel) {
return mAppSaturationController
.setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser,
@@ -1509,9 +1511,7 @@
}
final long token = Binder.clearCallingIdentity();
try {
- final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
- message.arg1 = level;
- mHandler.sendMessage(message);
+ setSaturationLevelInternal(level);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1724,5 +1724,22 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public int handleShellCommand(ParcelFileDescriptor in,
+ ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args) {
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+ "Permission required to use ADB color transform commands");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return new ColorDisplayShellCommand(ColorDisplayService.this)
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(),
+ args);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
new file mode 100644
index 0000000..b4555f8
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
@@ -0,0 +1,119 @@
+/*
+ * 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.display.color;
+
+import android.content.pm.PackageManagerInternal;
+import android.os.ShellCommand;
+
+import com.android.server.LocalServices;
+
+class ColorDisplayShellCommand extends ShellCommand {
+
+ private static final String USAGE = "usage: cmd color_display SUBCOMMAND [ARGS]\n"
+ + " help\n"
+ + " Shows this message.\n"
+ + " set-saturation LEVEL\n"
+ + " Sets the device saturation to the given LEVEL, 0-100 inclusive.\n"
+ + " set-layer-saturation CALLER_PACKAGE TARGET_PACKAGE LEVEL\n"
+ + " Sets the saturation LEVEL for all layers of the TARGET_PACKAGE, attributed\n"
+ + " to the CALLER_PACKAGE. The lowest LEVEL from any CALLER_PACKAGE is applied.\n";
+
+ private static final int ERROR = -1;
+ private static final int SUCCESS = 0;
+
+ private final ColorDisplayService mService;
+
+ ColorDisplayShellCommand(ColorDisplayService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "set-saturation":
+ return setSaturation();
+ case "set-layer-saturation":
+ return setLayerSaturation();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int setSaturation() {
+ final int level = getLevel();
+ if (level == ERROR) {
+ return ERROR;
+ }
+ mService.setSaturationLevelInternal(level);
+ return SUCCESS;
+ }
+
+ private int setLayerSaturation() {
+ final int level = getLevel();
+ if (level == ERROR) {
+ return ERROR;
+ }
+ final String callerPackageName = getPackageName();
+ if (callerPackageName == null) {
+ getErrPrintWriter().println("Error: CALLER_PACKAGE must be an installed package name");
+ return ERROR;
+ }
+ final String targetPackageName = getPackageName();
+ if (targetPackageName == null) {
+ getErrPrintWriter().println("Error: TARGET_PACKAGE must be an installed package name");
+ return ERROR;
+ }
+ mService.setAppSaturationLevelInternal(callerPackageName, targetPackageName, level);
+ return SUCCESS;
+ }
+
+ private String getPackageName() {
+ final String packageNameArg = getNextArg();
+ return LocalServices.getService(PackageManagerInternal.class).getPackage(packageNameArg)
+ == null
+ ? null : packageNameArg;
+ }
+
+ private int getLevel() {
+ final String levelArg = getNextArg();
+ if (levelArg == null) {
+ getErrPrintWriter().println("Error: Required argument LEVEL is unspecified");
+ return ERROR;
+ }
+ final int level;
+ try {
+ level = Integer.parseInt(levelArg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: LEVEL argument is not an integer");
+ return ERROR;
+ }
+ if (level < 0 || level > 100) {
+ getErrPrintWriter()
+ .println("Error: LEVEL argument must be an integer between 0 and 100");
+ return ERROR;
+ }
+ return level;
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().print(USAGE);
+ }
+}
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 8a3c963..c0617ca 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -29,8 +29,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
-import android.gamedriver.GameDriverProto.Blacklist;
-import android.gamedriver.GameDriverProto.Blacklists;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
@@ -40,6 +38,8 @@
import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.text.TextUtils;
+import android.updatabledriver.UpdatableDriverProto.Denylist;
+import android.updatabledriver.UpdatableDriverProto.Denylists;
import android.util.Base64;
import android.util.Slog;
@@ -65,7 +65,7 @@
private static final String PROD_DRIVER_PROPERTY = "ro.gfx.driver.0";
private static final String DEV_DRIVER_PROPERTY = "ro.gfx.driver.1";
- private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_ALLOWLIST_FILENAME = "allowlist.txt";
private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
private final Context mContext;
@@ -81,7 +81,7 @@
private SettingsObserver mSettingsObserver;
private DeviceConfigListener mDeviceConfigListener;
@GuardedBy("mLock")
- private Blacklists mBlacklists;
+ private Denylists mDenylists;
public GpuService(Context context) {
super(context);
@@ -118,19 +118,19 @@
mSettingsObserver = new SettingsObserver();
mDeviceConfigListener = new DeviceConfigListener();
fetchGameDriverPackageProperties();
- processBlacklists();
- setBlacklist();
+ processDenylists();
+ setDenylist();
fetchDeveloperDriverPackageProperties();
}
}
private final class SettingsObserver extends ContentObserver {
- private final Uri mGameDriverBlackUri =
- Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_BLACKLISTS);
+ private final Uri mGameDriverDenylistsUri =
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_DENYLISTS);
SettingsObserver() {
super(new Handler());
- mContentResolver.registerContentObserver(mGameDriverBlackUri, false, this,
+ mContentResolver.registerContentObserver(mGameDriverDenylistsUri, false, this,
UserHandle.USER_ALL);
}
@@ -140,9 +140,9 @@
return;
}
- if (mGameDriverBlackUri.equals(uri)) {
- processBlacklists();
- setBlacklist();
+ if (mGameDriverDenylistsUri.equals(uri)) {
+ processDenylists();
+ setDenylist();
}
}
}
@@ -157,10 +157,10 @@
@Override
public void onPropertiesChanged(Properties properties) {
synchronized (mDeviceConfigLock) {
- if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) {
- parseBlacklists(
- properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, ""));
- setBlacklist();
+ if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_DENYLISTS)) {
+ parseDenylists(
+ properties.getString(Settings.Global.GAME_DRIVER_DENYLISTS, ""));
+ setDenylist();
}
}
}
@@ -187,7 +187,7 @@
case ACTION_PACKAGE_REMOVED:
if (isProdDriver) {
fetchGameDriverPackageProperties();
- setBlacklist();
+ setDenylist();
} else if (isDevDriver) {
fetchDeveloperDriverPackageProperties();
}
@@ -239,17 +239,17 @@
return;
}
- // Reset the whitelist.
+ // Reset the allowlist.
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_WHITELIST, "");
+ Settings.Global.GAME_DRIVER_ALLOWLIST, "");
mGameDriverVersionCode = driverInfo.longVersionCode;
try {
final Context driverContext = mContext.createPackageContext(mProdDriverPackageName,
Context.CONTEXT_RESTRICTED);
- assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_WHITELIST_FILENAME,
- Settings.Global.GAME_DRIVER_WHITELIST, ",");
+ assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_ALLOWLIST_FILENAME,
+ Settings.Global.GAME_DRIVER_ALLOWLIST, ",");
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
Slog.w(TAG, "driver package '" + mProdDriverPackageName + "' not installed");
@@ -257,48 +257,48 @@
}
}
- private void processBlacklists() {
+ private void processDenylists() {
String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER,
- Settings.Global.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS);
if (base64String == null) {
base64String =
Settings.Global.getString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS);
}
- parseBlacklists(base64String != null ? base64String : "");
+ parseDenylists(base64String != null ? base64String : "");
}
- private void parseBlacklists(String base64String) {
+ private void parseDenylists(String base64String) {
synchronized (mLock) {
- // Reset all blacklists
- mBlacklists = null;
+ // Reset all denylists
+ mDenylists = null;
try {
- mBlacklists = Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
+ mDenylists = Denylists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
} catch (IllegalArgumentException e) {
if (DEBUG) {
- Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ Slog.w(TAG, "Can't parse denylist, skip and continue...");
}
} catch (InvalidProtocolBufferException e) {
if (DEBUG) {
- Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ Slog.w(TAG, "Can't parse denylist, skip and continue...");
}
}
}
}
- private void setBlacklist() {
+ private void setDenylist() {
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLIST, "");
+ Settings.Global.GAME_DRIVER_DENYLIST, "");
synchronized (mLock) {
- if (mBlacklists == null) {
+ if (mDenylists == null) {
return;
}
- List<Blacklist> blacklists = mBlacklists.getBlacklistsList();
- for (Blacklist blacklist : blacklists) {
- if (blacklist.getVersionCode() == mGameDriverVersionCode) {
+ List<Denylist> denylists = mDenylists.getDenylistsList();
+ for (Denylist denylist : denylists) {
+ if (denylist.getVersionCode() == mGameDriverVersionCode) {
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- String.join(",", blacklist.getPackageNamesList()));
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ String.join(",", denylist.getPackageNamesList()));
return;
}
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index 3c4dae0..c90f297 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -39,15 +39,19 @@
@Override
boolean start() {
mState = STATE_STARTED;
- sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
- source().mService.getPhysicalAddress()));
+ int logicalAddress = getSourceAddress();
+ int physicalAddress = getSourcePath();
+
+ sendCommand(HdmiCecMessageBuilder.buildActiveSource(logicalAddress, physicalAddress));
if (source().getType() == HdmiDeviceInfo.DEVICE_PLAYBACK) {
// Reports menu-status active to receive <User Control Pressed>.
sendCommand(
- HdmiCecMessageBuilder.buildReportMenuStatus(getSourceAddress(), mDestination,
+ HdmiCecMessageBuilder.buildReportMenuStatus(logicalAddress, mDestination,
Constants.MENU_STATE_ACTIVATED));
}
+
+ source().setActiveSource(logicalAddress, physicalAddress);
mState = STATE_FINISHED;
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 64d70d6..596c1ec 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -85,6 +85,14 @@
// The option is false by default. Update settings db as well to have the right
// initial setting on UI.
mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, mAutoTvOff);
+
+ // Initialize settings database with System Property value. This will be the initial
+ // setting on the UI. If no System Property is set, the option is set to to_tv by default.
+ mService.writeStringSetting(Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ mService.readStringSetting(Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiProperties.send_standby_on_sleep().orElse(
+ HdmiProperties.send_standby_on_sleep_values.TO_TV).name()
+ .toLowerCase()));
}
@Override
@@ -188,8 +196,26 @@
}
switch (standbyAction) {
case HdmiControlService.STANDBY_SCREEN_OFF:
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ // Get latest setting value
+ @HdmiControlManager.StandbyBehavior
+ String sendStandbyOnSleep = mService.readStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiProperties.send_standby_on_sleep().orElse(
+ HdmiProperties.send_standby_on_sleep_values.TO_TV).name()
+ .toLowerCase());
+ switch (sendStandbyOnSleep) {
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV:
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ break;
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST:
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress,
+ Constants.ADDR_BROADCAST));
+ break;
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE:
+ break;
+ }
break;
case HdmiControlService.STANDBY_SHUTDOWN:
// ACTION_SHUTDOWN is taken as a signal to power off all the devices.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index a8a9a36..0576e91 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -772,6 +772,11 @@
return content;
}
+ void writeStringSetting(String key, String value) {
+ ContentResolver cr = getContext().getContentResolver();
+ Global.putString(cr, key, value);
+ }
+
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -3244,7 +3249,6 @@
playback.setIsActiveSource(true);
playback.wakeUpIfActiveSource();
playback.maySendActiveSource(source);
- setActiveSource(playback.mAddress, physicalAddress);
}
if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
@@ -3255,7 +3259,6 @@
audioSystem.setIsActiveSource(true);
audioSystem.wakeUpIfActiveSource();
audioSystem.maySendActiveSource(source);
- setActiveSource(audioSystem.mAddress, physicalAddress);
}
}
}
@@ -3278,13 +3281,11 @@
if (audioSystem != null) {
audioSystem.setIsActiveSource(false);
}
- setActiveSource(playback.mAddress, physicalAddress);
} else {
if (audioSystem != null) {
audioSystem.setIsActiveSource(true);
audioSystem.wakeUpIfActiveSource();
audioSystem.maySendActiveSource(sourceAddress);
- setActiveSource(audioSystem.mAddress, physicalAddress);
}
}
}
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 2672f84..7bbcdaa 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -43,6 +43,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -299,16 +300,16 @@
}
@Override // from SystemService
- public void onUnlockUser(int userId) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
synchronized (mLock) {
- updateCachedServiceLocked(userId);
+ updateCachedServiceLocked(user.getUserIdentifier());
}
}
@Override // from SystemService
- public void onCleanupUser(int userId) {
+ public void onUserStopped(@NonNull TargetUser user) {
synchronized (mLock) {
- removeCachedServiceLocked(userId);
+ removeCachedServiceLocked(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 254285d..3cd70fe 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -159,6 +159,7 @@
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
@@ -1596,10 +1597,11 @@
}
@Override
- public void onSwitchUser(@UserIdInt int userHandle) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
// Called on ActivityManager thread.
synchronized (mService.mMethodMap) {
- mService.scheduleSwitchUserTaskLocked(userHandle, null /* clientToBeReset */);
+ mService.scheduleSwitchUserTaskLocked(to.getUserIdentifier(),
+ /* clientToBeReset= */ null);
}
}
@@ -1615,10 +1617,10 @@
}
@Override
- public void onUnlockUser(final @UserIdInt int userHandle) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
// Called on ActivityManager thread.
mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER,
- userHandle /* arg1 */, 0 /* arg2 */));
+ /* arg1= */ user.getUserIdentifier(), /* arg2= */ 0));
}
}
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2516e28..937514c 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -94,6 +94,7 @@
import com.android.internal.view.InputBindResult;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
@@ -249,23 +250,26 @@
@MainThread
@Override
- public void onStartUser(@UserIdInt int userId) {
+ public void onUserStarting(@NonNull TargetUser user) {
mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
- OnWorkerThreadCallback::onStartUser, mOnWorkerThreadCallback, userId));
+ OnWorkerThreadCallback::onStartUser, mOnWorkerThreadCallback,
+ user.getUserIdentifier()));
}
@MainThread
@Override
- public void onUnlockUser(@UserIdInt int userId) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
- OnWorkerThreadCallback::onUnlockUser, mOnWorkerThreadCallback, userId));
+ OnWorkerThreadCallback::onUnlockUser, mOnWorkerThreadCallback,
+ user.getUserIdentifier()));
}
@MainThread
@Override
- public void onStopUser(@UserIdInt int userId) {
+ public void onUserStopping(@NonNull TargetUser user) {
mOnWorkerThreadCallback.getHandler().sendMessage(PooledLambda.obtainMessage(
- OnWorkerThreadCallback::onStopUser, mOnWorkerThreadCallback, userId));
+ OnWorkerThreadCallback::onStopUser, mOnWorkerThreadCallback,
+ user.getUserIdentifier()));
}
}
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index e29471b..eed1aac 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.hardware.location.ActivityRecognitionHardware;
import android.hardware.location.IActivityRecognitionHardwareClient;
@@ -77,7 +78,7 @@
return mServiceWatcher.register();
}
- private void onBind(IBinder binder) throws RemoteException {
+ private void onBind(IBinder binder, ComponentName service) throws RemoteException {
String descriptor = binder.getInterfaceDescriptor();
if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 2bcee2f..d778d24 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.location.Location;
import android.location.util.identity.CallerIdentity;
@@ -32,10 +33,12 @@
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.ArrayUtils;
import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Proxy for ILocationProvider implementations.
@@ -65,6 +68,8 @@
@GuardedBy("mLock")
Proxy mProxy;
+ @GuardedBy("mLock")
+ @Nullable ComponentName mService;
private volatile ProviderRequest mRequest;
@@ -86,11 +91,12 @@
return mServiceWatcher.register();
}
- private void onBind(IBinder binder) throws RemoteException {
+ private void onBind(IBinder binder, ComponentName service) throws RemoteException {
ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
synchronized (mLock) {
mProxy = new Proxy();
+ mService = service;
provider.setLocationProviderManager(mProxy);
ProviderRequest request = mRequest;
@@ -103,6 +109,7 @@
private void onUnbind() {
synchronized (mLock) {
mProxy = null;
+ mService = null;
setState(State.EMPTY_STATE);
}
}
@@ -111,16 +118,16 @@
public void onSetRequest(ProviderRequest request) {
mRequest = request;
mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.setRequest(request, request.workSource);
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+ provider.setRequest(request, request.workSource);
});
}
@Override
public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.sendExtraCommand(command, extras);
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+ provider.sendExtraCommand(command, extras);
});
}
@@ -129,12 +136,14 @@
mServiceWatcher.dump(fd, pw, args);
}
- private static String guessPackageName(Context context, int uid) {
+ private static String guessPackageName(Context context, int uid, String packageName) {
String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
if (packageNames == null || packageNames.length == 0) {
// illegal state exception will propagate back through binders
throw new IllegalStateException(
"location provider from uid " + uid + " has no package information");
+ } else if (ArrayUtils.contains(packageNames, packageName)) {
+ return packageName;
} else {
return packageNames[0];
}
@@ -154,7 +163,8 @@
CallerIdentity identity;
if (packageName == null) {
- packageName = guessPackageName(mContext, Binder.getCallingUid());
+ packageName = guessPackageName(mContext, Binder.getCallingUid(),
+ Objects.requireNonNull(mService).getPackageName());
// unsafe is ok since the package is coming direct from the package manager here
identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
} else {
@@ -175,7 +185,8 @@
// if no identity is set yet, set it now
if (getIdentity() == null) {
- String packageName = guessPackageName(mContext, Binder.getCallingUid());
+ String packageName = guessPackageName(mContext, Binder.getCallingUid(),
+ Objects.requireNonNull(mService).getPackageName());
// unsafe is ok since the package is coming direct from the package manager here
setIdentity(CallerIdentity.fromBinderUnsafe(packageName, null));
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index 2218079..686a66b 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -63,7 +63,7 @@
private GeofenceProxy(Context context, IGpsGeofenceHardware gpsGeofence) {
mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence);
mServiceWatcher = new ServiceWatcher(context, SERVICE_ACTION,
- this::updateGeofenceHardware, null,
+ (binder, service) -> updateGeofenceHardware(binder), null,
com.android.internal.R.bool.config_enableGeofenceOverlay,
com.android.internal.R.string.config_geofenceProviderPackageName);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index e568848..f1b89c7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -123,6 +123,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
@@ -275,18 +276,18 @@
}
@Override
- public void onStartUser(int userHandle) {
- mLockSettingsService.onStartUser(userHandle);
+ public void onUserStarting(@NonNull TargetUser user) {
+ mLockSettingsService.onStartUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userHandle) {
- mLockSettingsService.onUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mLockSettingsService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onCleanupUser(int userHandle) {
- mLockSettingsService.onCleanupUser(userHandle);
+ public void onUserStopped(@NonNull TargetUser user) {
+ mLockSettingsService.onCleanupUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 9dae1b4..b9997e0 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -221,8 +221,8 @@
context.startActivityAsUser(mediaButtonIntent, userHandle);
break;
case COMPONENT_TYPE_SERVICE:
- context.startForegroundServiceAsUser(mediaButtonIntent,
- userHandle);
+ context.createContextAsUser(userHandle, 0).startForegroundService(
+ mediaButtonIntent);
break;
default:
// Legacy behavior for other cases.
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
index 6669b8c..e5da9b1 100644
--- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -25,7 +25,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
-import android.util.Slog;
import com.android.server.SystemService;
@@ -53,7 +52,7 @@
public void notifyResourceGranted(int pid, int type)
throws RemoteException {
if (DEBUG) {
- Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ")");
+ Log.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ")");
}
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9f6c18d..e2f70e3 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -25,6 +25,8 @@
import static com.android.server.media.MediaKeyDispatcher.isSingleTapOverridden;
import static com.android.server.media.MediaKeyDispatcher.isTripleTapOverridden;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
@@ -85,6 +87,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
@@ -333,19 +336,21 @@
}
@Override
- public void onStartUser(int userId) {
- if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
+ public void onUserStarting(@NonNull TargetUser user) {
+ if (DEBUG) Log.d(TAG, "onStartUser: " + user);
updateUser();
}
@Override
- public void onSwitchUser(int userId) {
- if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ if (DEBUG) Log.d(TAG, "onSwitchUser: " + to);
updateUser();
}
@Override
- public void onCleanupUser(int userId) {
+ public void onUserStopped(@NonNull TargetUser targetUser) {
+ int userId = targetUser.getUserIdentifier();
+
if (DEBUG) Log.d(TAG, "onCleanupUser: " + userId);
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(userId);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 1a749b3..94776f8 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,6 +17,8 @@
package com.android.server.media.projection;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
@@ -48,6 +50,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.Watchdog;
import java.io.FileDescriptor;
@@ -122,8 +125,8 @@
}
@Override
- public void onSwitchUser(int userId) {
- mMediaRouter.rebindAsUser(userId);
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mMediaRouter.rebindAsUser(to.getUserIdentifier());
synchronized (mLock) {
if (mProjectionGrant != null) {
mProjectionGrant.stop();
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 05ab2ae..342a11b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -28,6 +28,7 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.TAG;
@@ -185,35 +186,6 @@
}
}
- /**
- * Safely multiple a value by a rational.
- * <p>
- * Internally it uses integer-based math whenever possible, but switches
- * over to double-based math if values would overflow.
- */
- @VisibleForTesting
- public static long multiplySafe(long value, long num, long den) {
- if (den == 0) den = 1;
- long x = value;
- long y = num;
-
- // Logic shamelessly borrowed from Math.multiplyExact()
- long r = x * y;
- long ax = Math.abs(x);
- long ay = Math.abs(y);
- if (((ax | ay) >>> 31 != 0)) {
- // Some bits greater than 2^31 that might cause overflow
- // Check the result using the divide operator
- // and check for the special case of Long.MIN_VALUE * -1
- if (((y != 0) && (r / y != x)) ||
- (x == Long.MIN_VALUE && y == -1)) {
- // Use double math to avoid overflowing
- return (long) (((double) num / den) * value);
- }
- }
- return r / den;
- }
-
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
return getRelevantUids(accessLevel, Binder.getCallingUid());
}
@@ -311,11 +283,13 @@
}
final long rawBytes = entry.rxBytes + entry.txBytes;
- final long rawRxBytes = entry.rxBytes;
- final long rawTxBytes = entry.txBytes;
+ final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
+ final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
final long targetBytes = augmentPlan.getDataUsageBytes();
- final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes);
- final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes);
+
+ final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes);
+ final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes);
+
// Scale all matching buckets to reach anchor target
final long beforeTotal = combined.getTotalBytes();
@@ -323,8 +297,10 @@
combined.getValues(i, entry);
if (entry.bucketStart >= augmentStart
&& entry.bucketStart + entry.bucketDuration <= augmentEnd) {
- entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes);
- entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes);
+ entry.rxBytes = multiplySafeByRational(
+ targetRxBytes, entry.rxBytes, rawRxBytes);
+ entry.txBytes = multiplySafeByRational(
+ targetTxBytes, entry.txBytes, rawTxBytes);
// We purposefully clear out packet counters to indicate
// that this data has been augmented.
entry.rxPackets = 0;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 86ad0b3..e9868fd 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -59,7 +59,7 @@
private static final String TAG = "NetworkStatsFactory";
private static final boolean USE_NATIVE_PARSING = true;
- private static final boolean SANITY_CHECK_NATIVE = false;
+ private static final boolean VALIDATE_NATIVE_STATS = false;
/** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
private final File mStatsXtIfaceAll;
@@ -347,7 +347,7 @@
INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) {
throw new IOException("Failed to parse network stats");
}
- if (SANITY_CHECK_NATIVE) {
+ if (VALIDATE_NATIVE_STATS) {
final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid,
UID_ALL, INTERFACES_ALL, TAG_ALL);
assertEquals(javaStats, stats);
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 9eff5d1..ce74169 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -227,7 +227,7 @@
for (int i = 0; i < delta.size(); i++) {
entry = delta.getValues(i, entry);
- // As a last-ditch sanity check, report any negative values and
+ // As a last-ditch check, report any negative values and
// clamp them so recording below doesn't croak.
if (entry.isNegative()) {
if (mObserver != null) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cf08e73..d71c33e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -261,6 +261,7 @@
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.UiThread;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -322,7 +323,7 @@
static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
"debug.notification.interruptiveness", false);
- static final int MAX_PACKAGE_NOTIFICATIONS = 25;
+ static final int MAX_PACKAGE_NOTIFICATIONS = 50;
static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
// message codes
@@ -2351,11 +2352,11 @@
}
@Override
- public void onUnlockUser(@NonNull UserInfo userInfo) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
mHandler.post(() -> {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryUnlockUser");
try {
- mHistoryManager.onUserUnlocked(userInfo.id);
+ mHistoryManager.onUserUnlocked(user.getUserIdentifier());
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -2363,11 +2364,11 @@
}
@Override
- public void onStopUser(@NonNull UserInfo userInfo) {
+ public void onUserStopping(@NonNull TargetUser user) {
mHandler.post(() -> {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryStopUser");
try {
- mHistoryManager.onUserStopped(userInfo.id);
+ mHistoryManager.onUserStopped(user.getUserIdentifier());
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -4861,7 +4862,6 @@
// calculate the final importance here
r.calculateImportance();
foundEnqueued = true;
- break;
}
}
if (!foundEnqueued) {
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index d6b1b27..cb6e960 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -27,6 +27,7 @@
import android.os.Build.VERSION_CODES;
import android.os.OverlayablePolicy;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.IOException;
@@ -53,11 +54,20 @@
}
private final IdmapDaemon mIdmapDaemon;
- private final OverlayableInfoCallback mOverlayableCallback;
+ private final PackageManagerHelper mPackageManager;
- IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) {
- mOverlayableCallback = verifyCallback;
+ /**
+ * Package name of the reference package defined in 'config-signature' tag of
+ * SystemConfig or empty String if tag not defined. This package is vetted on scan by
+ * PackageManagerService that it's a system package and is used to check if overlay matches
+ * its signature in order to fulfill the config_signature policy.
+ */
+ private final String mConfigSignaturePackage;
+
+ IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) {
+ mPackageManager = packageManager;
mIdmapDaemon = idmapDaemon;
+ mConfigSignaturePackage = packageManager.getConfigSignaturePackage();
}
/**
@@ -139,7 +149,7 @@
int fulfilledPolicies = OverlayablePolicy.PUBLIC;
// Overlay matches target signature
- if (mOverlayableCallback.signaturesMatching(targetPackage.packageName,
+ if (mPackageManager.signaturesMatching(targetPackage.packageName,
overlayPackage.packageName, userId)) {
fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
}
@@ -149,6 +159,16 @@
fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
}
+ // If SystemConfig defines 'config-signature' package, given that
+ // this package is vetted by OverlayManagerService that it's a
+ // preinstalled package, check if overlay matches its signature.
+ if (!TextUtils.isEmpty(mConfigSignaturePackage)
+ && mPackageManager.signaturesMatching(mConfigSignaturePackage,
+ overlayPackage.packageName,
+ userId)) {
+ fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE;
+ }
+
// Vendor partition (/vendor)
if (ai.isVendor()) {
return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
@@ -183,12 +203,12 @@
String targetOverlayableName = overlayPackage.targetOverlayableName;
if (targetOverlayableName != null) {
try {
- OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget(
+ OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
targetPackage.packageName, targetOverlayableName, userId);
if (overlayableInfo != null && overlayableInfo.actor != null) {
String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
- overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first;
- if (mOverlayableCallback.signaturesMatching(actorPackageName,
+ overlayableInfo.actor, mPackageManager.getNamedActors()).first;
+ if (mPackageManager.signaturesMatching(actorPackageName,
overlayPackage.packageName, userId)) {
return true;
}
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 2bc3499..8c03c6c 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -45,7 +45,7 @@
// By default, the reason is not logged to prevent leaks of why it failed
private static final boolean DEBUG_REASON = false;
- private final OverlayableInfoCallback mOverlayableCallback;
+ private final PackageManagerHelper mPackageManager;
/**
* @return nullable actor result with {@link ActorState} failure status
@@ -79,8 +79,8 @@
return Pair.create(packageName, ActorState.ALLOWED);
}
- public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) {
- mOverlayableCallback = overlayableCallback;
+ public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) {
+ mPackageManager = packageManager;
}
void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
@@ -110,7 +110,7 @@
return ActorState.ALLOWED;
}
- String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid);
+ String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
if (ArrayUtils.isEmpty(callingPackageNames)) {
return ActorState.NO_PACKAGES_FOR_UID;
}
@@ -125,12 +125,12 @@
if (TextUtils.isEmpty(targetOverlayableName)) {
try {
- if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
+ if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) {
return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
} else {
// If there's no overlayable defined, fallback to the legacy permission check
try {
- mOverlayableCallback.enforcePermission(
+ mPackageManager.enforcePermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
// If the previous method didn't throw, check passed
@@ -146,7 +146,7 @@
OverlayableInfo targetOverlayable;
try {
- targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName,
+ targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
targetOverlayableName, userId);
} catch (IOException e) {
return ActorState.UNABLE_TO_GET_TARGET;
@@ -160,7 +160,7 @@
if (TextUtils.isEmpty(actor)) {
// If there's no actor defined, fallback to the legacy permission check
try {
- mOverlayableCallback.enforcePermission(
+ mPackageManager.enforcePermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
// If the previous method didn't throw, check passed
@@ -170,7 +170,7 @@
}
}
- Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors();
+ Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors();
Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
ActorState actorUriState = actorUriPair.second;
if (actorUriState != ActorState.ALLOWED) {
@@ -178,7 +178,7 @@
}
String packageName = actorUriPair.first;
- PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId);
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId);
if (packageInfo == null) {
return ActorState.MISSING_APP_INFO;
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3968153..a4debc1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
@@ -68,6 +69,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.UserManagerService;
import libcore.util.EmptyArray;
@@ -303,7 +305,11 @@
}
@Override
- public void onSwitchUser(final int newUserId) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ onSwitchUser(to.getUserIdentifier());
+ }
+
+ private void onSwitchUser(@UserIdInt int newUserId) {
try {
traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
// ensure overlays in the settings are up-to-date, and propagate
@@ -1053,8 +1059,7 @@
}
}
- private static final class PackageManagerHelperImpl implements PackageManagerHelper,
- OverlayableInfoCallback {
+ private static final class PackageManagerHelperImpl implements PackageManagerHelper {
private final Context mContext;
private final IPackageManager mPackageManager;
@@ -1127,6 +1132,14 @@
return overlays;
}
+ @Override
+ public String getConfigSignaturePackage() {
+ final String[] pkgs = mPackageManagerInternal.getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
+ UserHandle.USER_SYSTEM);
+ return (pkgs.length == 0) ? null : pkgs[0];
+ }
+
@Nullable
@Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index cadb8e4..a9dbb2f 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -18,14 +18,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import android.text.TextUtils;
import android.util.Pair;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.server.SystemConfig;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Collections;
import java.util.HashMap;
@@ -72,6 +73,8 @@
*/
public class OverlayReferenceMapper {
+ private static final String TAG = "OverlayReferenceMapper";
+
private final Object mLock = new Object();
/**
@@ -144,7 +147,7 @@
public boolean isValidActor(@NonNull String targetName, @NonNull String actorPackageName) {
synchronized (mLock) {
- assertMapBuilt();
+ ensureMapBuilt();
Set<String> validSet = mActorPkgToPkgs.get(actorPackageName);
return validSet != null && validSet.contains(targetName);
}
@@ -292,10 +295,11 @@
}
}
- private void assertMapBuilt() {
+ private void ensureMapBuilt() {
if (mDeferRebuild) {
- throw new IllegalStateException("The actor map must be built by calling "
- + "rebuildIfDeferred before it is queried");
+ rebuildIfDeferred();
+ Slog.w(TAG, "The actor map was queried before the system was ready, which may"
+ + "result in decreased performance.");
}
}
@@ -360,7 +364,7 @@
* Given the actor string from an overlayable definition, return the actor's package name.
*/
@Nullable
- String getActorPkg(String actor);
+ String getActorPkg(@NonNull String actor);
/**
* Mock response of multiple overlay tags.
diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java
deleted file mode 100644
index 5066ecd..0000000
--- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java
+++ /dev/null
@@ -1,83 +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.om;
-
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.om.OverlayableInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-
-import com.android.server.pm.PackageManagerServiceUtils;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Delegate to the system for querying information about overlayables and packages.
- */
-public interface OverlayableInfoCallback {
-
- /**
- * Read from the APK and AndroidManifest of a package to return the overlayable defined for
- * a given name.
- *
- * @throws IOException if the target can't be read
- */
- @Nullable
- OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
- @NonNull String targetOverlayableName, int userId)
- throws IOException;
-
- /**
- * @see PackageManager#getPackagesForUid(int)
- */
- @Nullable
- String[] getPackagesForUid(int uid);
-
- /**
- * @param userId user to filter package visibility by
- * @see PackageManager#getPackageInfo(String, int)
- */
- @Nullable
- PackageInfo getPackageInfo(@NonNull String packageName, int userId);
-
- /**
- * @return map of system pre-defined, uniquely named actors; keys are namespace,
- * value maps actor name to package name
- */
- @NonNull
- Map<String, Map<String, String>> getNamedActors();
-
- /**
- * @return true if the target package has declared an overlayable
- */
- boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
-
- /**
- * @throws SecurityException containing message if the caller doesn't have the given
- * permission
- */
- void enforcePermission(String permission, String message) throws SecurityException;
-
- /**
- * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
- * in the system returns {@link PackageManager#SIGNATURE_MATCH}
- */
- boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
-}
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
index ec9c5e6..b1a8b4e 100644
--- a/services/core/java/com/android/server/om/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -17,11 +17,17 @@
package com.android.server.om;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayableInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.IOException;
import java.util.List;
+import java.util.Map;
/**
* Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality,
@@ -30,7 +36,65 @@
* @hide
*/
interface PackageManagerHelper {
- PackageInfo getPackageInfo(@NonNull String packageName, int userId);
- boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+ /**
+ * @return true if the target package has declared an overlayable
+ */
+ boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException;
+
+ /**
+ * @throws SecurityException containing message if the caller doesn't have the given
+ * permission
+ */
+ void enforcePermission(String permission, String message) throws SecurityException;
+
+ /**
+ * Returns the package name of the reference package defined in 'overlay-config-signature' tag
+ * of SystemConfig. This package is vetted on scan by PackageManagerService that it's a system
+ * package and is used to check if overlay matches its signature in order to fulfill the
+ * config_signature policy.
+ */
+ @Nullable
+ String getConfigSignaturePackage();
+
+ /**
+ * @return map of system pre-defined, uniquely named actors; keys are namespace,
+ * value maps actor name to package name
+ */
+ @NonNull
+ Map<String, Map<String, String>> getNamedActors();
+
+ /**
+ * @see PackageManagerInternal#getOverlayPackages(int)
+ */
List<PackageInfo> getOverlayPackages(int userId);
+
+ /**
+ * Read from the APK and AndroidManifest of a package to return the overlayable defined for
+ * a given name.
+ *
+ * @throws IOException if the target can't be read
+ */
+ @Nullable
+ OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+ @NonNull String targetOverlayableName, int userId)
+ throws IOException;
+
+ /**
+ * @see PackageManager#getPackagesForUid(int)
+ */
+ @Nullable
+ String[] getPackagesForUid(int uid);
+
+ /**
+ * @param userId user to filter package visibility by
+ * @see PackageManager#getPackageInfo(String, int)
+ */
+ @Nullable
+ PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+
+ /**
+ * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages
+ * in the system returns {@link PackageManager#SIGNATURE_MATCH}
+ */
+ boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
}
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index a837fb4..d937af1 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -1,6 +1,14 @@
{
"presubmit": [
- // TODO(159590499) add BugreportManagerTestCases
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
{
"file_patterns": ["Bugreport[^/]*\\.java"],
"name": "CtsBugreportTestCases",
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index c3c2e5e..92c0c6a 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -137,11 +137,11 @@
@VisibleForTesting(visibility = PRIVATE)
AppsFilter(StateProvider stateProvider,
FeatureConfig featureConfig,
- String[] forceQueryableWhitelist,
+ String[] forceQueryableList,
boolean systemAppsQueryable,
@Nullable OverlayReferenceMapper.Provider overlayProvider) {
mFeatureConfig = featureConfig;
- mForceQueryableByDevicePackageNames = forceQueryableWhitelist;
+ mForceQueryableByDevicePackageNames = forceQueryableList;
mSystemAppsQueryable = systemAppsQueryable;
mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
overlayProvider);
@@ -746,11 +746,11 @@
* @param users the set of users that should be evaluated for this calculation
* @param existingSettings the set of all package settings that currently exist on device
* @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
- * provided setting or null if the app is visible to all and no whitelist should be
+ * provided setting or null if the app is visible to all and no allow list should be
* applied.
*/
@Nullable
- public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users,
+ public SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users,
ArrayMap<String, PackageSetting> existingSettings) {
if (mForceQueryable.contains(setting.appId)) {
return null;
@@ -761,14 +761,14 @@
final int userId = users[u];
int[] appIds = new int[existingSettings.size()];
int[] buffer = null;
- int whitelistSize = 0;
+ int allowListSize = 0;
for (int i = existingSettings.size() - 1; i >= 0; i--) {
final PackageSetting existingSetting = existingSettings.valueAt(i);
final int existingAppId = existingSetting.appId;
if (existingAppId < Process.FIRST_APPLICATION_UID) {
continue;
}
- final int loc = Arrays.binarySearch(appIds, 0, whitelistSize, existingAppId);
+ final int loc = Arrays.binarySearch(appIds, 0, allowListSize, existingAppId);
if (loc >= 0) {
continue;
}
@@ -778,13 +778,13 @@
buffer = new int[appIds.length];
}
final int insert = ~loc;
- System.arraycopy(appIds, insert, buffer, 0, whitelistSize - insert);
+ System.arraycopy(appIds, insert, buffer, 0, allowListSize - insert);
appIds[insert] = existingAppId;
- System.arraycopy(buffer, 0, appIds, insert + 1, whitelistSize - insert);
- whitelistSize++;
+ System.arraycopy(buffer, 0, appIds, insert + 1, allowListSize - insert);
+ allowListSize++;
}
}
- result.put(userId, Arrays.copyOf(appIds, whitelistSize));
+ result.put(userId, Arrays.copyOf(appIds, allowListSize));
}
return result;
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 5415967..d48570f 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -337,6 +337,7 @@
private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
long lowStorageThreshold) {
ArraySet<String> updatedPackages = new ArraySet<>();
+ ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
final boolean supportSecondaryDex = supportSecondaryDex();
@@ -391,11 +392,14 @@
}
int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackages);
+ /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex);
return secondaryResult;
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
+ // Only notify IORap the primary dex opt, because we don't want to
+ // invalidate traces unnecessary due to b/161633001 and that it's
+ // better to have a trace than no trace at all.
notifyPackagesUpdated(updatedPackages);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 92da005..7765f18 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -157,6 +157,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@@ -262,6 +263,12 @@
private final Object mLock = new Object();
+ /**
+ * Used to detect and reject concurrent access to this session object to ensure mutation
+ * to multiple objects like {@link #addChildSessionId} are done atomically.
+ */
+ private final AtomicBoolean mTransactionLock = new AtomicBoolean(false);
+
/** Timestamp of the last time this session changed state */
@GuardedBy("mLock")
private long updatedMillis;
@@ -1746,7 +1753,7 @@
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
try {
- installNonStaged(childSessions);
+ verifyNonStaged(childSessions);
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
@@ -1755,23 +1762,64 @@
}
}
- private void installNonStaged(List<PackageInstallerSession> childSessions)
+ private void verifyNonStaged(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
- final PackageManagerService.ActiveInstallSession installingSession =
- makeSessionActive();
- if (installingSession == null) {
+ final PackageManagerService.VerificationParams verifyingSession =
+ makeVerificationParams();
+ if (verifyingSession == null) {
return;
}
if (isMultiPackage()) {
- List<PackageManagerService.ActiveInstallSession> installingChildSessions =
+ List<PackageManagerService.VerificationParams> verifyingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
- final PackageManagerService.ActiveInstallSession installingChildSession =
- session.makeSessionActive();
+ final PackageManagerService.VerificationParams verifyingChildSession =
+ session.makeVerificationParams();
+ if (verifyingChildSession != null) {
+ verifyingChildSessions.add(verifyingChildSession);
+ }
+ } catch (PackageManagerException e) {
+ failure = e;
+ success = false;
+ }
+ }
+ if (!success) {
+ final IntentSender statusReceiver;
+ synchronized (mLock) {
+ statusReceiver = mRemoteStatusReceiver;
+ }
+ sendOnPackageInstalled(mContext, statusReceiver, sessionId,
+ isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
+ failure.error, failure.getLocalizedMessage(), null);
+ return;
+ }
+ mPm.verifyStage(verifyingSession, verifyingChildSessions);
+ } else {
+ mPm.verifyStage(verifyingSession);
+ }
+ }
+
+ private void installNonStaged(List<PackageInstallerSession> childSessions)
+ throws PackageManagerException {
+ final PackageManagerService.InstallParams installingSession =
+ makeInstallParams();
+ if (installingSession == null) {
+ return;
+ }
+ if (isMultiPackage()) {
+ List<PackageManagerService.InstallParams> installingChildSessions =
+ new ArrayList<>(childSessions.size());
+ boolean success = true;
+ PackageManagerException failure = null;
+ for (int i = 0; i < childSessions.size(); ++i) {
+ final PackageInstallerSession session = childSessions.get(i);
+ try {
+ final PackageManagerService.InstallParams installingChildSession =
+ session.makeInstallParams();
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
}
@@ -1797,11 +1845,12 @@
}
/**
- * Stages this session for install and returns a
- * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
- * in case permissions need to be requested before install can proceed.
+ * Stages this session for verification and returns a
+ * {@link PackageManagerService.VerificationParams} representing this new staged state or null
+ * in case permissions need to be requested before verification can proceed.
*/
- private PackageManagerService.ActiveInstallSession makeSessionActive()
+ @Nullable
+ private PackageManagerService.VerificationParams makeVerificationParams()
throws PackageManagerException {
assertNotLocked("makeSessionActive");
@@ -1820,6 +1869,7 @@
}
}
+ // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
if (!params.isMultiPackage && needToAskForPermissions()) {
// User needs to confirm installation;
// give installer an intent they can use to involve
@@ -1841,12 +1891,12 @@
}
synchronized (mLock) {
- return makeSessionActiveLocked();
+ return makeVerificationParamsLocked();
}
}
@GuardedBy("mLock")
- private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
+ private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
if (!params.isMultiPackage) {
Objects.requireNonNull(mPackageName);
@@ -1910,6 +1960,78 @@
extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
}
+ final IPackageInstallObserver2 localObserver;
+ if (!hasParentSessionId()) {
+ // Avoid attaching this observer to child session since they won't use it.
+ localObserver = new IPackageInstallObserver2.Stub() {
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+ Bundle extras) {
+ if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ onVerificationComplete();
+ } else {
+ destroyInternal();
+ dispatchSessionFinished(returnCode, msg, extras);
+ }
+ }
+ };
+ } else {
+ localObserver = null;
+ }
+
+ final UserHandle user;
+ if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
+ user = UserHandle.ALL;
+ } else {
+ user = new UserHandle(userId);
+ }
+
+ mRelinquished = true;
+
+ return mPm.new VerificationParams(user, stageDir, localObserver, params,
+ mInstallSource, mInstallerUid, mSigningDetails, sessionId);
+ }
+
+ private void onVerificationComplete() {
+ if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle());
+ return;
+ }
+
+ List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
+ try {
+ installNonStaged(childSessions);
+ } catch (PackageManagerException e) {
+ final String completeMsg = ExceptionUtils.getCompleteMessage(e);
+ Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
+ destroyInternal();
+ dispatchSessionFinished(e.error, completeMsg, null);
+ }
+ }
+
+ /**
+ * Stages this session for install and returns a
+ * {@link PackageManagerService.InstallParams} representing this new staged state.
+ */
+ private PackageManagerService.InstallParams makeInstallParams()
+ throws PackageManagerException {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
+ }
+ if (!mSealed) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
+ }
+ }
+
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@@ -1926,34 +2048,6 @@
}
};
- // An observer through which PMS returns the result of verification
- // TODO(samiul): We are temporarily assigning two observer to ActiveInstallSession. One for
- // installation and one for verification. This will be fixed within next few CLs.
- final IPackageInstallObserver2 sessionVerificationObserver;
- if (!hasParentSessionId()) {
- // Avoid attaching this observer to child session since they won't use it.
- sessionVerificationObserver = new IPackageInstallObserver2.Stub() {
- @Override
- public void onUserActionRequired(Intent intent) {
- throw new IllegalStateException();
- }
-
- @Override
- public void onPackageInstalled(String basePackageName, int returnCode, String msg,
- Bundle extras) {
- if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
- // TODO(samiul): In future, packages will not be installed immediately after
- // verification. Package verification will return control back to here,
- // and we will have call into PMS again to install package.
- //
- // For now, this is a no op.
- }
- }
- };
- } else {
- sessionVerificationObserver = null;
- }
-
final UserHandle user;
if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
@@ -1961,10 +2055,10 @@
user = new UserHandle(userId);
}
- mRelinquished = true;
- return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
- sessionVerificationObserver, sessionId, params, mInstallerUid, mInstallSource, user,
- mSigningDetails);
+ synchronized (mLock) {
+ return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
+ mSigningDetails, mInstallerUid);
+ }
}
private static void maybeRenameFile(File from, File to) throws PackageManagerException {
@@ -3073,39 +3167,85 @@
}
}
+ private void acquireTransactionLock() {
+ if (!mTransactionLock.compareAndSet(false, true)) {
+ throw new UnsupportedOperationException("Concurrent access not supported");
+ }
+ }
+
+ private void releaseTransactionLock() {
+ mTransactionLock.compareAndSet(true, false);
+ }
+
@Override
public void addChildSessionId(int childSessionId) {
- final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
- if (childSession == null || !childSession.canBeAddedAsChild(sessionId)) {
- throw new IllegalStateException("Unable to add child session " + childSessionId
- + " as it does not exist or is in an invalid state.");
+ if (!params.isMultiPackage) {
+ throw new IllegalStateException("Single-session " + sessionId + " can't have child.");
}
- synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
- assertPreparedAndNotSealedLocked("addChildSessionId");
- final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
- if (indexOfSession >= 0) {
- return;
+ final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
+ if (childSession == null) {
+ throw new IllegalStateException("Unable to add child session " + childSessionId
+ + " as it does not exist.");
+ }
+ if (childSession.params.isMultiPackage) {
+ throw new IllegalStateException("Multi-session " + childSessionId
+ + " can't be a child.");
+ }
+
+ try {
+ acquireTransactionLock();
+ childSession.acquireTransactionLock();
+
+ if (!childSession.canBeAddedAsChild(sessionId)) {
+ throw new IllegalStateException("Unable to add child session " + childSessionId
+ + " as it is in an invalid state.");
}
- childSession.setParentSessionId(this.sessionId);
- addChildSessionIdLocked(childSessionId);
+ synchronized (mLock) {
+ assertCallerIsOwnerOrRootLocked();
+ assertPreparedAndNotSealedLocked("addChildSessionId");
+
+ final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
+ if (indexOfSession >= 0) {
+ return;
+ }
+ childSession.setParentSessionId(this.sessionId);
+ addChildSessionIdLocked(childSessionId);
+ }
+ } finally {
+ releaseTransactionLock();
+ childSession.releaseTransactionLock();
}
}
@Override
public void removeChildSessionId(int sessionId) {
final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
- synchronized (mLock) {
- final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ try {
+ acquireTransactionLock();
if (session != null) {
- session.setParentSessionId(SessionInfo.INVALID_ID);
+ session.acquireTransactionLock();
}
- if (indexOfSession < 0) {
- // not added in the first place; no-op
- return;
+
+ synchronized (mLock) {
+ assertCallerIsOwnerOrRootLocked();
+ assertPreparedAndNotSealedLocked("removeChildSessionId");
+
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (indexOfSession < 0) {
+ // not added in the first place; no-op
+ return;
+ }
+ if (session != null) {
+ session.setParentSessionId(SessionInfo.INVALID_ID);
+ }
+ mChildSessionIds.removeAt(indexOfSession);
}
- mChildSessionIds.removeAt(indexOfSession);
+ } finally {
+ releaseTransactionLock();
+ if (session != null) {
+ session.releaseTransactionLock();
+ }
}
}
@@ -3260,7 +3400,7 @@
private void destroyInternal() {
synchronized (mLock) {
mSealed = true;
- if (!params.isStaged || isStagedAndInTerminalState()) {
+ if (!params.isStaged) {
mDestroyed = true;
}
// Force shut down all bridges
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 73db48a..a726c8d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -120,6 +120,7 @@
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
@@ -331,6 +332,7 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
@@ -1127,6 +1129,7 @@
public @Nullable String storageManagerPackage;
public @Nullable String defaultTextClassifierPackage;
public @Nullable String systemTextClassifierPackage;
+ public @Nullable String overlayConfigSignaturePackage;
public ViewCompiler viewCompiler;
public @Nullable String wellbeingPackage;
public @Nullable String retailDemoPackage;
@@ -1159,7 +1162,7 @@
final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
/** List of packages waiting for rollback to be enabled. */
- final SparseArray<InstallParams> mPendingEnableRollback = new SparseArray<>();
+ final SparseArray<VerificationParams> mPendingEnableRollback = new SparseArray<>();
final PackageInstallerService mInstallerService;
@@ -1659,6 +1662,7 @@
final @Nullable String mServicesExtensionPackageName;
final @Nullable String mSharedSystemSharedLibraryPackageName;
final @Nullable String mRetailDemoPackage;
+ final @Nullable String mOverlayConfigSignaturePackage;
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
@@ -1833,7 +1837,7 @@
if ((state != null) && !state.isVerificationComplete()
&& !state.timeoutExtended()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
@@ -1874,7 +1878,7 @@
final PackageVerificationState state = mPendingVerification.get(verificationId);
if (state != null && !state.isIntegrityVerificationComplete()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Integrity verification timed out for " + originUri);
@@ -1919,7 +1923,7 @@
state.setVerifierResponse(response.callerUid, response.code);
if (state.isVerificationComplete()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
if (state.isInstallAllowed()) {
@@ -1953,7 +1957,7 @@
}
final int response = (Integer) msg.obj;
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
state.setIntegrityVerificationResult(response);
@@ -2037,7 +2041,8 @@
case ENABLE_ROLLBACK_STATUS: {
final int enableRollbackToken = msg.arg1;
final int enableRollbackCode = msg.arg2;
- InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ final VerificationParams params =
+ mPendingEnableRollback.get(enableRollbackToken);
if (params == null) {
Slog.w(TAG, "Invalid rollback enabled token "
+ enableRollbackToken + " received");
@@ -2061,7 +2066,8 @@
case ENABLE_ROLLBACK_TIMEOUT: {
final int enableRollbackToken = msg.arg1;
final int sessionId = msg.arg2;
- final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ final VerificationParams params =
+ mPendingEnableRollback.get(enableRollbackToken);
if (params != null) {
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
@@ -2210,17 +2216,17 @@
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
// Send to all running apps.
- final SparseArray<int[]> newBroadcastWhitelist;
+ final SparseArray<int[]> newBroadcastAllowList;
synchronized (mLock) {
- newBroadcastWhitelist = mAppsFilter.getVisibilityWhitelist(
+ newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(res.name, Process.SYSTEM_UID),
updateUserIds, mSettings.mPackages);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, newBroadcastWhitelist);
+ updateUserIds, instantUserIds, newBroadcastAllowList);
if (installerPackageName != null) {
// Send to the installer, even if it's not running.
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -2252,7 +2258,7 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, res.removedInfo.broadcastWhitelist);
+ updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList);
if (installerPackageName != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
@@ -2588,7 +2594,7 @@
(i, pm) ->
new Settings(Environment.getDataDirectory(),
i.getPermissionManagerServiceInternal().getPermissionSettings(),
- lock),
+ RuntimePermissionsPersistence.createInstance(), lock),
new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
@@ -2814,6 +2820,7 @@
mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
+ mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
mResolveComponentName = testParams.resolveComponentName;
mPackages.putAll(testParams.packages);
@@ -3379,6 +3386,7 @@
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mRetailDemoPackage = getRetailDemoPackageName();
+ mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -4205,13 +4213,9 @@
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
- final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
- if (ps != null) {
- final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)
- || Build.IS_ENG) {
- continue;
- }
+ if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
+ rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+ continue;
}
iter.remove();
}
@@ -8591,10 +8595,9 @@
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
- final PermissionsState permissionsState = ps.getPermissionsState();
for (int i=0; i<permissions.length; i++) {
final String permission = permissions[i];
- if (permissionsState.hasPermission(permission, userId)) {
+ if (checkPermission(permission, ps.name, userId) == PERMISSION_GRANTED) {
tmp[i] = true;
numMatch++;
} else {
@@ -12119,12 +12122,8 @@
if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
// Exempt SharedUsers signed with the platform key.
PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
- if ((platformPkgSetting.signatures.mSigningDetails
- != PackageParser.SigningDetails.UNKNOWN)
- && (compareSignatures(
- platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.getSigningDetails().signatures)
- != PackageManager.SIGNATURE_MATCH)) {
+ if (!comparePackageSignatures(platformPkgSetting,
+ pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Apps that share a user with a " +
"privileged app must themselves be marked as privileged. " +
pkg.getPackageName() + " shares privileged user " +
@@ -12171,12 +12170,8 @@
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
final PackageSetting platformPkgSetting =
mSettings.getPackageLPr("android");
- if ((platformPkgSetting.signatures.mSigningDetails
- != PackageParser.SigningDetails.UNKNOWN)
- && (compareSignatures(
- platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.getSigningDetails().signatures)
- != PackageManager.SIGNATURE_MATCH)) {
+ if (!comparePackageSignatures(platformPkgSetting,
+ pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Overlay "
+ pkg.getPackageName()
+ " must target Q or later, "
@@ -12185,24 +12180,35 @@
}
// A non-preloaded overlay package, without <overlay android:targetName>, will
- // only be used if it is signed with the same certificate as its target. If the
- // target is already installed, check this here to augment the last line of
- // defence which is OMS.
+ // only be used if it is signed with the same certificate as its target OR if
+ // it is signed with the same certificate as a reference package declared
+ // in 'config-signature' tag of SystemConfig.
+ // If the target is already installed or 'config-signature' tag in SystemConfig
+ // is set, check this here to augment the last line of defence which is OMS.
if (pkg.getOverlayTargetName() == null) {
final PackageSetting targetPkgSetting =
mSettings.getPackageLPr(pkg.getOverlayTarget());
if (targetPkgSetting != null) {
- if ((targetPkgSetting.signatures.mSigningDetails
- != PackageParser.SigningDetails.UNKNOWN)
- && (compareSignatures(
- targetPkgSetting.signatures.mSigningDetails.signatures,
- pkg.getSigningDetails().signatures)
- != PackageManager.SIGNATURE_MATCH)) {
- throw new PackageManagerException("Overlay "
- + pkg.getPackageName() + " and target "
- + pkg.getOverlayTarget() + " signed with"
- + " different certificates, and the overlay lacks"
- + " <overlay android:targetName>");
+ if (!comparePackageSignatures(targetPkgSetting,
+ pkg.getSigningDetails().signatures)) {
+ // check reference signature
+ if (mOverlayConfigSignaturePackage == null) {
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName() + " and target "
+ + pkg.getOverlayTarget() + " signed with"
+ + " different certificates, and the overlay lacks"
+ + " <overlay android:targetName>");
+ }
+ final PackageSetting refPkgSetting =
+ mSettings.getPackageLPr(mOverlayConfigSignaturePackage);
+ if (!comparePackageSignatures(refPkgSetting,
+ pkg.getSigningDetails().signatures)) {
+ throw new PackageManagerException("Overlay "
+ + pkg.getPackageName() + " signed with a different "
+ + "certificate than both the reference package and "
+ + "target " + pkg.getOverlayTarget() + ", and the "
+ + "overlay lacks <overlay android:targetName>");
+ }
}
}
}
@@ -12672,7 +12678,7 @@
public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
final int[] userIds, int[] instantUserIds,
- @Nullable SparseArray<int[]> broadcastWhitelist) {
+ @Nullable SparseArray<int[]> broadcastAllowList) {
mHandler.post(() -> {
try {
final IActivityManager am = ActivityManager.getService();
@@ -12684,7 +12690,7 @@
resolvedUserIds = userIds;
}
doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
- resolvedUserIds, false, broadcastWhitelist);
+ resolvedUserIds, false, broadcastAllowList);
if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
instantUserIds, true, null);
@@ -12757,7 +12763,7 @@
*/
private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
int flags, String targetPkg, IIntentReceiver finishedReceiver,
- int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastWhitelist) {
+ int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList) {
for (int id : userIds) {
final Intent intent = new Intent(action,
pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
@@ -12787,7 +12793,7 @@
mInjector.getActivityManagerInternal().broadcastIntent(
intent, finishedReceiver, requiredPermissions,
finishedReceiver != null, id,
- broadcastWhitelist == null ? null : broadcastWhitelist.get(id));
+ broadcastAllowList == null ? null : broadcastAllowList.get(id));
}
}
@@ -12850,15 +12856,8 @@
return installReason;
}
- void installStage(ActiveInstallSession activeInstallSession) {
- if (DEBUG_INSTANT) {
- if ((activeInstallSession.getSessionParams().installFlags
- & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
- }
- }
+ void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
- final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12870,11 +12869,11 @@
mHandler.sendMessage(msg);
}
- void installStage(ActiveInstallSession parent, List<ActiveInstallSession> children)
+ void installStage(InstallParams parent, List<InstallParams> children)
throws PackageManagerException {
final Message msg = mHandler.obtainMessage(INIT_COPY);
final MultiPackageInstallParams params =
- new MultiPackageInstallParams(UserHandle.ALL, parent, children);
+ new MultiPackageInstallParams(parent, children);
params.setTraceMethod("installStageMultiPackage")
.setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12886,6 +12885,21 @@
mHandler.sendMessage(msg);
}
+ void verifyStage(VerificationParams params) {
+ mHandler.post(()-> {
+ params.startCopy();
+ });
+ }
+
+ void verifyStage(VerificationParams parent, List<VerificationParams> children)
+ throws PackageManagerException {
+ final MultiPackageVerificationParams params =
+ new MultiPackageVerificationParams(parent, children);
+ mHandler.post(()-> {
+ params.startCopy();
+ });
+ }
+
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId, int dataLoaderType) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -12919,7 +12933,7 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, userIds, instantUserIds,
- mAppsFilter.getVisibilityWhitelist(
+ mAppsFilter.getVisibilityAllowList(
getPackageSettingInternal(packageName, Process.SYSTEM_UID),
userIds, mSettings.mPackages));
if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
@@ -14746,32 +14760,21 @@
* committed together.
*/
class MultiPackageInstallParams extends HandlerParams {
- private final IPackageInstallObserver2 mVerificationObserver;
- @NonNull
- private final ArrayList<InstallParams> mChildParams;
- // TODO(samiul): mCurrentState will relocated to a install-specific class in future
- @NonNull
+ private final List<InstallParams> mChildParams;
private final Map<InstallArgs, Integer> mCurrentState;
- private final Map<InstallParams, Integer> mVerificationState;
- MultiPackageInstallParams(
- @NonNull UserHandle user,
- @NonNull ActiveInstallSession parent,
- @NonNull List<ActiveInstallSession> activeInstallSessions)
+ MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
throws PackageManagerException {
- super(user);
- if (activeInstallSessions.size() == 0) {
+ super(parent.getUser());
+ if (childParams.size() == 0) {
throw new PackageManagerException("No child sessions found!");
}
- mChildParams = new ArrayList<>(activeInstallSessions.size());
- for (int i = 0; i < activeInstallSessions.size(); i++) {
- final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
- childParams.mParentInstallParams = this;
- this.mChildParams.add(childParams);
+ mChildParams = childParams;
+ for (int i = 0; i < childParams.size(); i++) {
+ final InstallParams childParam = childParams.get(i);
+ childParam.mParentInstallParams = this;
}
this.mCurrentState = new ArrayMap<>(mChildParams.size());
- this.mVerificationState = new ArrayMap<>(mChildParams.size());
- mVerificationObserver = parent.getVerificationObserver();
}
@Override
@@ -14788,7 +14791,6 @@
}
}
- // TODO(samiul): this method will relocated to a install-specific class in future
void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
mCurrentState.put(args, currentStatus);
if (mCurrentState.size() != mChildParams.size()) {
@@ -14812,122 +14814,67 @@
completeStatus == PackageManager.INSTALL_SUCCEEDED,
installRequests);
}
-
- void trySendVerificationCompleteNotification(InstallParams child, int currentStatus) {
- mVerificationState.put(child, currentStatus);
- if (mVerificationState.size() != mChildParams.size()) {
- return;
- }
- int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mVerificationState.values()) {
- if (status == PackageManager.INSTALL_UNKNOWN) {
- return;
- } else if (status != PackageManager.INSTALL_SUCCEEDED) {
- completeStatus = status;
- break;
- }
- }
- try {
- mVerificationObserver.onPackageInstalled(null, completeStatus,
- "Package Verification Result", new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
}
class InstallParams extends HandlerParams {
- // TODO: see if we can collapse this into ActiveInstallSession
-
final OriginInfo origin;
final MoveInfo move;
- final IPackageInstallObserver2 mInstallObserver;
- private final IPackageInstallObserver2 mVerificationObserver;
+ final IPackageInstallObserver2 observer;
int installFlags;
@NonNull final InstallSource installSource;
final String volumeUuid;
- private boolean mWaitForVerificationToComplete;
- private boolean mWaitForIntegrityVerificationToComplete;
- private boolean mWaitForEnableRollbackToComplete;
int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final List<String> whitelistedRestrictedPermissions;
final int autoRevokePermissionsMode;
- final VerificationInfo verificationInfo;
final PackageParser.SigningDetails signingDetails;
final int installReason;
- @Nullable
- MultiPackageInstallParams mParentInstallParams;
- final long requiredInstalledVersionCode;
+ @Nullable MultiPackageInstallParams mParentInstallParams;
final boolean forceQueryableOverride;
final int mDataLoaderType;
- final int mSessionId;
- InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 installObserver,
+ InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid,
- VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
- int autoRevokePermissionsMode,
- SigningDetails signingDetails, int installReason,
- long requiredInstalledVersionCode, int dataLoaderType) {
+ UserHandle user, String packageAbiOverride) {
super(user);
this.origin = origin;
this.move = move;
- this.mInstallObserver = installObserver;
- this.mVerificationObserver = null;
+ this.observer = observer;
this.installFlags = installFlags;
this.installSource = Preconditions.checkNotNull(installSource);
this.volumeUuid = volumeUuid;
- this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
- this.grantedRuntimePermissions = grantedPermissions;
- this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
- this.autoRevokePermissionsMode = autoRevokePermissionsMode;
- this.signingDetails = signingDetails;
- this.installReason = installReason;
- this.requiredInstalledVersionCode = requiredInstalledVersionCode;
+
+ this.grantedRuntimePermissions = null;
+ this.whitelistedRestrictedPermissions = null;
+ this.autoRevokePermissionsMode = MODE_DEFAULT;
+ this.signingDetails = PackageParser.SigningDetails.UNKNOWN;
+ this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
this.forceQueryableOverride = false;
- this.mDataLoaderType = dataLoaderType;
- this.mSessionId = -1;
+ this.mDataLoaderType = DataLoaderType.NONE;
}
- InstallParams(ActiveInstallSession activeInstallSession) {
- super(activeInstallSession.getUser());
- final PackageInstaller.SessionParams sessionParams =
- activeInstallSession.getSessionParams();
- if (DEBUG_INSTANT) {
- if ((sessionParams.installFlags
- & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
- }
- }
- verificationInfo = new VerificationInfo(
- sessionParams.originatingUri,
- sessionParams.referrerUri,
- sessionParams.originatingUid,
- activeInstallSession.getInstallerUid());
- origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+ InstallParams(File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ UserHandle user, SigningDetails signingDetails, int installerUid) {
+ super(user);
+ origin = OriginInfo.fromStagedFile(stagedDir);
move = null;
installReason = fixUpInstallReason(
- activeInstallSession.getInstallSource().installerPackageName,
- activeInstallSession.getInstallerUid(),
- sessionParams.installReason);
- mInstallObserver = activeInstallSession.getInstallObserver();
- mVerificationObserver = activeInstallSession.getVerificationObserver();
+ installSource.installerPackageName, installerUid, sessionParams.installReason);
+ this.observer = observer;
installFlags = sessionParams.installFlags;
- installSource = activeInstallSession.getInstallSource();
+ this.installSource = installSource;
volumeUuid = sessionParams.volumeUuid;
packageAbiOverride = sessionParams.abiOverride;
grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
- signingDetails = activeInstallSession.getSigningDetails();
- requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ this.signingDetails = signingDetails;
forceQueryableOverride = sessionParams.forceQueryableOverride;
mDataLoaderType = (sessionParams.dataLoaderParams != null)
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
- mSessionId = activeInstallSession.getSessionId();
}
@Override
@@ -15074,13 +15021,147 @@
public void handleStartCopy() {
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
+ mRet = overrideInstallLocation(pkgLite);
+ }
+
+ @Override
+ void handleReturnCode() {
+ processPendingInstall();
+ }
+
+ private void processPendingInstall() {
+ InstallArgs args = createInstallArgs(this);
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ mRet = args.copyApk();
+ }
+ if (mParentInstallParams != null) {
+ mParentInstallParams.tryProcessInstallRequest(args, mRet);
+ } else {
+ PackageInstalledInfo res = createPackageInstalledInfo(mRet);
+ processInstallRequestsAsync(
+ res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+
+ }
+ }
+ }
+
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ class MultiPackageVerificationParams extends HandlerParams {
+ private final IPackageInstallObserver2 mObserver;
+ private final List<VerificationParams> mChildParams;
+ private final Map<VerificationParams, Integer> mVerificationState;
+
+ MultiPackageVerificationParams(
+ VerificationParams parent,
+ List<VerificationParams> children)
+ throws PackageManagerException {
+ super(parent.getUser());
+ if (children.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = children;
+ // Provide every child with reference to this object as parent
+ for (int i = 0; i < children.size(); i++) {
+ final VerificationParams childParams = children.get(i);
+ childParams.mParentVerificationParams = this;
+ }
+ this.mVerificationState = new ArrayMap<>(mChildParams.size());
+ mObserver = parent.observer;
+ }
+
+ @Override
+ void handleStartCopy() {
+ for (VerificationParams params : mChildParams) {
+ params.handleStartCopy();
+ }
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (VerificationParams params : mChildParams) {
+ params.handleReturnCode();
+ }
+ }
+
+ void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
+ mVerificationState.put(child, currentStatus);
+ if (mVerificationState.size() != mChildParams.size()) {
+ return;
+ }
+ int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+ for (Integer status : mVerificationState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ completeStatus = status;
+ break;
+ }
+ }
+ try {
+ mObserver.onPackageInstalled(null, completeStatus,
+ "Package Verification Result", new Bundle());
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ class VerificationParams extends HandlerParams {
+ final OriginInfo origin;
+ final IPackageInstallObserver2 observer;
+ final int installFlags;
+ @NonNull final InstallSource installSource;
+ final String packageAbiOverride;
+ final VerificationInfo verificationInfo;
+ final PackageParser.SigningDetails signingDetails;
+ @Nullable MultiPackageVerificationParams mParentVerificationParams;
+ final long requiredInstalledVersionCode;
+ final int mDataLoaderType;
+ final int mSessionId;
+
+ private boolean mWaitForVerificationToComplete;
+ private boolean mWaitForIntegrityVerificationToComplete;
+ private boolean mWaitForEnableRollbackToComplete;
+ private int mRet;
+
+ VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ int installerUid, SigningDetails signingDetails, int sessionId) {
+ super(user);
+ origin = OriginInfo.fromStagedFile(stagedDir);
+ this.observer = observer;
+ installFlags = sessionParams.installFlags;
+ this.installSource = installSource;
+ packageAbiOverride = sessionParams.abiOverride;
+ verificationInfo = new VerificationInfo(
+ sessionParams.originatingUri,
+ sessionParams.referrerUri,
+ sessionParams.originatingUid,
+ installerUid
+ );
+ this.signingDetails = signingDetails;
+ requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ mDataLoaderType = (sessionParams.dataLoaderParams != null)
+ ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+ mSessionId = sessionId;
+ }
+
+ @Override
+ public String toString() {
+ return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+ + " file=" + origin.file + "}";
+ }
+
+ public void handleStartCopy() {
+ PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+ origin.resolvedPath, installFlags, packageAbiOverride);
mRet = verifyReplacingVersionCode(pkgLite);
- if (mRet == INSTALL_SUCCEEDED) {
- mRet = overrideInstallLocation(pkgLite);
- }
-
// Perform package verification and enable rollback (unless we are simply moving the
// package).
if (mRet == INSTALL_SUCCEEDED && !origin.existing) {
@@ -15242,7 +15323,7 @@
final long idleDuration = getVerificationTimeout();
idleController.addPowerSaveTempWhitelistAppDirect(Process.myUid(),
- idleDuration,
+ idleDuration,
false, "integrity component");
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppWhitelistDuration(idleDuration);
@@ -15476,44 +15557,16 @@
|| mWaitForEnableRollbackToComplete) {
return;
}
-
- if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
- try {
- mInstallObserver.onPackageInstalled(null, mRet, "Dry run", new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- return;
- }
sendVerificationCompleteNotification();
-
- // TODO(samiul): In future return once verification is complete
- processPendingInstall();
- }
-
- private void processPendingInstall() {
- InstallArgs args = createInstallArgs(this);
- if (mRet == PackageManager.INSTALL_SUCCEEDED) {
- mRet = args.copyApk();
- }
- if (mParentInstallParams != null) {
- mParentInstallParams.tryProcessInstallRequest(args, mRet);
- } else {
- PackageInstalledInfo res = createPackageInstalledInfo(mRet);
- processInstallRequestsAsync(
- res.returnCode == PackageManager.INSTALL_SUCCEEDED,
- Collections.singletonList(new InstallRequest(args, res)));
-
- }
}
private void sendVerificationCompleteNotification() {
- if (mParentInstallParams != null) {
- mParentInstallParams.trySendVerificationCompleteNotification(this, mRet);
+ if (mParentVerificationParams != null) {
+ mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
} else {
try {
- mVerificationObserver.onPackageInstalled(null, mRet,
- "Package Verification Result", new Bundle());
+ observer.onPackageInstalled(null, mRet, "Package Verification Result",
+ new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
@@ -15597,7 +15650,7 @@
/** New install */
InstallArgs(InstallParams params) {
- this(params.origin, params.move, params.mInstallObserver, params.installFlags,
+ this(params.origin, params.move, params.observer, params.installFlags,
params.installSource, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
@@ -16713,7 +16766,7 @@
reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
- res.removedInfo.broadcastWhitelist = mAppsFilter.getVisibilityWhitelist(
+ res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
reconciledPkg.pkgSetting, request.mAllUsers, mSettings.mPackages);
if (reconciledPkg.prepareResult.system) {
// Remove existing system package
@@ -18643,7 +18696,7 @@
boolean isStaticSharedLib;
// a two dimensional array mapping userId to the set of appIds that can receive notice
// of package changes
- SparseArray<int[]> broadcastWhitelist;
+ SparseArray<int[]> broadcastAllowList;
// Clean up resources deleted packages.
InstallArgs args = null;
@@ -18666,9 +18719,9 @@
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
- 0, null /*targetPackage*/, null, null, null, broadcastWhitelist);
+ 0, null /*targetPackage*/, null, null, null, broadcastAllowList);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
- extras, 0, null /*targetPackage*/, null, null, null, broadcastWhitelist);
+ extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList);
packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
removedPackage, null, null, null, null /* broadcastWhitelist */);
if (installerPackageName != null) {
@@ -18700,7 +18753,7 @@
if (removedPackage != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
removedPackage, extras, 0, null /*targetPackage*/, null,
- broadcastUsers, instantUserIds, broadcastWhitelist);
+ broadcastUsers, instantUserIds, broadcastAllowList);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
removedPackage, extras, 0 /*flags*/,
@@ -18709,7 +18762,7 @@
if (dataRemoved && !isRemovedPackageSystemUpdate) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
- null, broadcastUsers, instantUserIds, broadcastWhitelist);
+ null, broadcastUsers, instantUserIds, broadcastAllowList);
packageSender.notifyPackageRemoved(removedPackage, removedUid);
}
}
@@ -18722,7 +18775,7 @@
packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null, null, broadcastUsers, instantUserIds, broadcastWhitelist);
+ null, null, broadcastUsers, instantUserIds, broadcastAllowList);
}
}
@@ -19221,6 +19274,13 @@
final int flags = action.flags;
final boolean systemApp = isSystemApp(ps);
+ // We need to get the permission state before package state is (potentially) destroyed.
+ final SparseBooleanArray hadSuspendAppsPermission = new SparseBooleanArray();
+ for (int userId : allUserHandles) {
+ hadSuspendAppsPermission.put(userId, checkPermission(Manifest.permission.SUSPEND_APPS,
+ packageName, userId) == PERMISSION_GRANTED);
+ }
+
final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
@@ -19287,8 +19347,7 @@
affectedUserIds = resolveUserIds(userId);
}
for (final int affectedUserId : affectedUserIds) {
- if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS,
- affectedUserId)) {
+ if (hadSuspendAppsPermission.get(affectedUserId)) {
unsuspendForSuspendingPackage(packageName, affectedUserId);
removeAllDistractingPackageRestrictions(affectedUserId);
}
@@ -20755,6 +20814,11 @@
return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
}
+ public String getOverlayConfigSignaturePackageName() {
+ return ensureSystemPackageName(SystemConfig.getInstance()
+ .getOverlayConfigSignaturePackage());
+ }
+
@Nullable
private String getRetailDemoPackageName() {
final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
@@ -21061,8 +21125,8 @@
pkgSetting.setEnabled(newState, userId, callingPackage);
if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED)
- && pkgSetting.getPermissionsState().hasPermission(
- Manifest.permission.SUSPEND_APPS, userId)) {
+ && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
// This app should not generally be allowed to get disabled by the UI, but if it
// ever does, we don't want to end up with some of the user's apps permanently
// suspended.
@@ -21214,17 +21278,17 @@
final boolean isInstantApp = isInstantApp(packageName, userId);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- final SparseArray<int[]> broadcastWhitelist;
+ final SparseArray<int[]> broadcastAllowList;
synchronized (mLock) {
PackageSetting setting = getPackageSettingInternal(packageName, Process.SYSTEM_UID);
if (setting == null) {
return;
}
- broadcastWhitelist = isInstantApp ? null : mAppsFilter.getVisibilityWhitelist(setting,
+ broadcastAllowList = isInstantApp ? null : mAppsFilter.getVisibilityAllowList(setting,
userIds, mSettings.mPackages);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null,
- userIds, instantUserIds, broadcastWhitelist);
+ userIds, instantUserIds, broadcastAllowList);
}
@Override
@@ -23377,12 +23441,7 @@
final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
- installSource, volumeUuid, null /*verificationInfo*/, user,
- packageAbiOverride, null /*grantedPermissions*/,
- null /*whitelistedRestrictedPermissions*/, MODE_DEFAULT /* autoRevokePermissions */,
- PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST,
- DataLoaderType.NONE);
+ installSource, volumeUuid, user, packageAbiOverride);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -24275,6 +24334,8 @@
return TextUtils.isEmpty(mRetailDemoPackage)
? ArrayUtils.emptyArray(String.class)
: new String[] {mRetailDemoPackage};
+ case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+ return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
default:
return ArrayUtils.emptyArray(String.class);
}
@@ -25628,79 +25689,6 @@
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
}
-
- static class ActiveInstallSession {
- private final String mPackageName;
- private final File mStagedDir;
- private final IPackageInstallObserver2 mInstallObserver;
- // TODO(samiul): We are temporarily assigning two observer to ActiveInstallSession. One for
- // installation and one for verification. This will be fixed within next few CLs.
- private final IPackageInstallObserver2 mVerificationObserver;
- private final int mSessionId;
- private final PackageInstaller.SessionParams mSessionParams;
- private final int mInstallerUid;
- @NonNull private final InstallSource mInstallSource;
- private final UserHandle mUser;
- private final SigningDetails mSigningDetails;
-
- ActiveInstallSession(String packageName, File stagedDir,
- IPackageInstallObserver2 installObserver,
- IPackageInstallObserver2 verificationObserver,
- int sessionId, PackageInstaller.SessionParams sessionParams, int installerUid,
- InstallSource installSource, UserHandle user, SigningDetails signingDetails) {
- mPackageName = packageName;
- mStagedDir = stagedDir;
- mInstallObserver = installObserver;
- mVerificationObserver = verificationObserver;
- mSessionId = sessionId;
- mSessionParams = sessionParams;
- mInstallerUid = installerUid;
- mInstallSource = Preconditions.checkNotNull(installSource);
- mUser = user;
- mSigningDetails = signingDetails;
- }
-
- public String getPackageName() {
- return mPackageName;
- }
-
- public File getStagedDir() {
- return mStagedDir;
- }
-
- public IPackageInstallObserver2 getInstallObserver() {
- return mInstallObserver;
- }
-
- public IPackageInstallObserver2 getVerificationObserver() {
- return mVerificationObserver;
- }
-
- public int getSessionId() {
- return mSessionId;
- }
-
- public PackageInstaller.SessionParams getSessionParams() {
- return mSessionParams;
- }
-
- public int getInstallerUid() {
- return mInstallerUid;
- }
-
- @NonNull
- public InstallSource getInstallSource() {
- return mInstallSource;
- }
-
- public UserHandle getUser() {
- return mUser;
- }
-
- public SigningDetails getSigningDetails() {
- return mSigningDetails;
- }
- }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 03f4708..de0e4b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -488,6 +488,18 @@
}
/**
+ * Returns true if the signature set of the package is identical to the specified signature
+ * set or if the signing details of the package are unknown.
+ */
+ public static boolean comparePackageSignatures(PackageSetting pkgSetting,
+ Signature[] signatures) {
+ return pkgSetting.signatures.mSigningDetails
+ == PackageParser.SigningDetails.UNKNOWN
+ || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures)
+ == PackageManager.SIGNATURE_MATCH;
+ }
+
+ /**
* Used for backward compatibility to make sure any packages with
* certificate chains get upgraded to the new style. {@code existingSigs}
* will be in the old format (since they were stored on disk from before the
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index ea7af90..cb9c2e9 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -19,7 +19,7 @@
import android.content.pm.PackageManager;
import android.util.SparseBooleanArray;
-import com.android.server.pm.PackageManagerService.InstallParams;
+import com.android.server.pm.PackageManagerService.VerificationParams;
/**
* Tracks the package verification state for a particular package. Each package verification has a
@@ -28,7 +28,7 @@
* sufficient verifiers, then package verification is considered complete.
*/
class PackageVerificationState {
- private final InstallParams mParams;
+ private final VerificationParams mParams;
private final SparseBooleanArray mSufficientVerifierUids;
@@ -50,13 +50,13 @@
* Create a new package verification state where {@code requiredVerifierUid} is the user ID for
* the package that must reply affirmative before things can continue.
*/
- PackageVerificationState(InstallParams params) {
+ PackageVerificationState(VerificationParams params) {
mParams = params;
mSufficientVerifierUids = new SparseBooleanArray();
mExtendedTimeout = false;
}
- InstallParams getInstallParams() {
+ VerificationParams getVerificationParams() {
return mParams;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7106499..1805713 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -435,10 +435,11 @@
}
Settings(File dataDir, PermissionSettings permission,
- Object lock) {
+ RuntimePermissionsPersistence runtimePermissionsPersistence, Object lock) {
mLock = lock;
mPermissions = permission;
- mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
+ mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
+ runtimePermissionsPersistence, mLock);
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
@@ -5381,8 +5382,7 @@
private String mExtendedFingerprint;
- private final RuntimePermissionsPersistence mPersistence =
- RuntimePermissionsPersistence.createInstance();
+ private final RuntimePermissionsPersistence mPersistence;
private final Handler mHandler = new MyHandler();
@@ -5407,7 +5407,9 @@
// The mapping keys are user ids.
private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
- public RuntimePermissionPersistence(Object persistenceLock) {
+ public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
+ Object persistenceLock) {
+ mPersistence = persistence;
mPersistenceLock = persistenceLock;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index f16b5b4..89ed3c7 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -108,6 +108,7 @@
import com.android.internal.util.StatLogger;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.ShortcutUser.PackageWithUser;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -614,13 +615,13 @@
}
@Override
- public void onStopUser(int userHandle) {
- mService.handleStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.handleStopUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userId) {
- mService.handleUnlockUser(userId);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.handleUnlockUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 616e5d1..89bdb3e 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -804,6 +804,7 @@
params.isStaged = false;
if (preReboot) {
params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ params.installFlags |= PackageManager.INSTALL_DRY_RUN;
}
final int apkParentSessionId = mPi.createSession(
params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b0d3d53..8f11fd5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -110,6 +110,7 @@
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.am.UserState;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -553,9 +554,9 @@
}
@Override
- public void onStartUser(@UserIdInt int userId) {
+ public void onUserStarting(@NonNull TargetUser targetUser) {
synchronized (mUms.mUsersLock) {
- final UserData user = mUms.getUserDataLU(userId);
+ final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
if (user != null) {
user.startRealtime = SystemClock.elapsedRealtime();
}
@@ -563,9 +564,9 @@
}
@Override
- public void onUnlockUser(@UserIdInt int userId) {
+ public void onUserUnlocking(@NonNull TargetUser targetUser) {
synchronized (mUms.mUsersLock) {
- final UserData user = mUms.getUserDataLU(userId);
+ final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
if (user != null) {
user.unlockRealtime = SystemClock.elapsedRealtime();
}
@@ -573,9 +574,9 @@
}
@Override
- public void onStopUser(@UserIdInt int userId) {
+ public void onUserStopping(@NonNull TargetUser targetUser) {
synchronized (mUms.mUsersLock) {
- final UserData user = mUms.getUserDataLU(userId);
+ final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
if (user != null) {
user.startRealtime = 0;
user.unlockRealtime = 0;
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
index fcc1f6c..5a4431e 100644
--- a/services/core/java/com/android/server/pm/dex/OWNERS
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -1,4 +1,2 @@
-agampe@google.com
calin@google.com
ngeoffray@google.com
-sehr@google.com
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 bc7554c..6e0efb0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -137,6 +137,7 @@
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
@@ -554,13 +555,14 @@
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
}
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
synchronized (mLock) {
final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
return null;
}
final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), packageName, callingUid);
+ bp.getProtectionLevel(), pkg, callingUid);
return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
}
}
@@ -920,6 +922,16 @@
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
+
+ try {
+ enforceCrossUserOrProfilePermission(Binder.getCallingUid(), UserHandle.getUserId(uid),
+ false, false, "checkPermissionInternal");
+ } catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "153996875", "checkPermission", uid);
+
+ throw e;
+ }
+
final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
pkg.getPackageName());
if (ps == null) {
@@ -1927,10 +1939,8 @@
}
}
if (doGrant && packageName != null) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
- userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
return true;
}
@@ -1940,10 +1950,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
}
@Override
@@ -1951,10 +1959,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"grantDefaultPermissionsToEnabledImsServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
}
@Override
@@ -1963,11 +1969,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"grantDefaultPermissionsToEnabledTelephonyDataServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledTelephonyDataServices(
- packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledTelephonyDataServices(packageNames, userId));
}
@Override
@@ -1976,11 +1979,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"revokeDefaultPermissionsFromDisabledTelephonyDataServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .revokeDefaultPermissionsFromDisabledTelephonyDataServices(
- packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .revokeDefaultPermissionsFromDisabledTelephonyDataServices(packageNames, userId));
}
@Override
@@ -1988,10 +1988,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
}
@Override
@@ -1999,10 +1997,8 @@
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
}
@Override
@@ -2229,8 +2225,8 @@
}
}
- private int adjustPermissionProtectionFlagsLocked(
- int protectionLevel, String packageName, int uid) {
+ private int adjustPermissionProtectionFlagsLocked(int protectionLevel,
+ @Nullable AndroidPackage pkg, int uid) {
// Signature permission flags area always reported
final int protectionLevelMasked = protectionLevel
& (PermissionInfo.PROTECTION_NORMAL
@@ -2245,8 +2241,6 @@
|| appId == Process.SHELL_UID) {
return protectionLevel;
}
- // Normalize package name to handle renamed packages and static libs
- final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null) {
return protectionLevel;
}
@@ -2254,14 +2248,6 @@
return protectionLevelMasked;
}
// Apps that target O see flags for all protection levels.
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
- return protectionLevel;
- }
- if (ps.getAppId() != appId) {
- return protectionLevel;
- }
return protectionLevel;
}
@@ -2586,8 +2572,8 @@
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
- updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
- ps.getSharedUser(), UserManagerService.getInstance().getUserIds());
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
+ currentUserIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -2597,150 +2583,152 @@
permissionsState.setGlobalGids(mGlobalGids);
- synchronized (mLock) {
- ArraySet<String> newImplicitPermissions = new ArraySet<>();
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
- final int N = pkg.getRequestedPermissions().size();
- for (int i = 0; i < N; i++) {
- final String permName = pkg.getRequestedPermissions().get(i);
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- final boolean appSupportsRuntimePermissions =
- pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
- String upgradedActivityRecognitionPermission = null;
+ final int N = pkg.getRequestedPermissions().size();
+ for (int i = 0; i < N; i++) {
+ final String permName = pkg.getRequestedPermissions().get(i);
+ final BasePermission bp = mSettings.getPermission(permName);
+ final boolean appSupportsRuntimePermissions =
+ pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
+ String upgradedActivityRecognitionPermission = null;
- if (DEBUG_INSTALL && bp != null) {
- Log.i(TAG, "Package " + pkg.getPackageName()
- + " checking " + permName + ": " + bp);
- }
+ if (DEBUG_INSTALL && bp != null) {
+ Log.i(TAG, "Package " + pkg.getPackageName()
+ + " checking " + permName + ": " + bp);
+ }
- if (bp == null || getSourcePackageSetting(bp) == null) {
- if (packageOfInterest == null || packageOfInterest.equals(
- pkg.getPackageName())) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Unknown permission " + permName
- + " in package " + pkg.getPackageName());
- }
- }
- continue;
- }
-
- // Cache newImplicitPermissions before modifing permissionsState as for the shared
- // uids the original and new state are the same object
- if (!origPermissions.hasRequestedPermission(permName)
- && (pkg.getImplicitPermissions().contains(permName)
- || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
- if (pkg.getImplicitPermissions().contains(permName)) {
- // If permName is an implicit permission, try to auto-grant
- newImplicitPermissions.add(permName);
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
- }
- } else {
- // Special case for Activity Recognition permission. Even if AR permission
- // is not an implicit permission we want to add it to the list (try to
- // auto-grant it) if the app was installed on a device before AR permission
- // was split, regardless of if the app now requests the new AR permission
- // or has updated its target SDK and AR is no longer implicit to it.
- // This is a compatibility workaround for apps when AR permission was
- // split in Q.
- final List<SplitPermissionInfoParcelable> permissionList =
- getSplitPermissions();
- int numSplitPerms = permissionList.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
- String splitPermName = sp.getSplitPermission();
- if (sp.getNewPermissions().contains(permName)
- && origPermissions.hasInstallPermission(splitPermName)) {
- upgradedActivityRecognitionPermission = splitPermName;
- newImplicitPermissions.add(permName);
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for "
- + pkg.getPackageName());
- }
- break;
- }
- }
- }
- }
-
- // TODO(b/140256621): The package instant app method has been removed
- // as part of work in b/135203078, so this has been commented out in the meantime
- // Limit ephemeral apps to ephemeral allowed permissions.
-// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
-// if (DEBUG_PERMISSIONS) {
-// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
-// + " for package " + pkg.getPackageName());
-// }
-// continue;
-// }
-
- if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
+ if (bp == null || getSourcePackageSetting(bp) == null) {
+ if (packageOfInterest == null || packageOfInterest.equals(
+ pkg.getPackageName())) {
if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.getName()
- + " for package " + pkg.getPackageName());
- }
- continue;
- }
-
- final String perm = bp.getName();
- boolean allowedSig = false;
- int grant = GRANT_DENIED;
-
- // Keep track of app op permissions.
- if (bp.isAppOp()) {
- mSettings.addAppOpPackage(perm, pkg.getPackageName());
- }
-
- if (bp.isNormal()) {
- // For all apps normal permissions are install time ones.
- grant = GRANT_INSTALL;
- } else if (bp.isRuntime()) {
- if (origPermissions.hasInstallPermission(bp.getName())
- || upgradedActivityRecognitionPermission != null) {
- // Before Q we represented some runtime permissions as install permissions,
- // in Q we cannot do this anymore. Hence upgrade them all.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
- }
- } else if (bp.isSignature()) {
- // For all apps signature permissions are install time ones.
- allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
- if (allowedSig) {
- grant = GRANT_INSTALL;
+ Slog.i(TAG, "Unknown permission " + permName
+ + " in package " + pkg.getPackageName());
}
}
+ continue;
+ }
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Considering granting permission " + perm + " to package "
- + pkg.getPackageName());
- }
+ // Cache newImplicitPermissions before modifing permissionsState as for the shared
+ // uids the original and new state are the same object
+ if (!origPermissions.hasRequestedPermission(permName)
+ && (pkg.getImplicitPermissions().contains(permName)
+ || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
+ if (pkg.getImplicitPermissions().contains(permName)) {
+ // If permName is an implicit permission, try to auto-grant
+ newImplicitPermissions.add(permName);
- if (grant != GRANT_DENIED) {
- if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
- // If this is an existing, non-system package, then
- // we can't add any new permissions to it. Runtime
- // permissions can be added any time - they ad dynamic.
- if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
- // Except... if this is a permission that was added
- // to the platform (note: need to only do this when
- // updating the platform).
- if (!isNewPlatformPermissionForPackage(perm, pkg)) {
- grant = GRANT_DENIED;
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
+ }
+ } else {
+ // Special case for Activity Recognition permission. Even if AR permission
+ // is not an implicit permission we want to add it to the list (try to
+ // auto-grant it) if the app was installed on a device before AR permission
+ // was split, regardless of if the app now requests the new AR permission
+ // or has updated its target SDK and AR is no longer implicit to it.
+ // This is a compatibility workaround for apps when AR permission was
+ // split in Q.
+ final List<SplitPermissionInfoParcelable> permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
+ String splitPermName = sp.getSplitPermission();
+ if (sp.getNewPermissions().contains(permName)
+ && origPermissions.hasInstallPermission(splitPermName)) {
+ upgradedActivityRecognitionPermission = splitPermName;
+ newImplicitPermissions.add(permName);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for "
+ + pkg.getPackageName());
}
+ break;
}
}
+ }
+ }
+ // TODO(b/140256621): The package instant app method has been removed
+ // as part of work in b/135203078, so this has been commented out in the meantime
+ // Limit ephemeral apps to ephemeral allowed permissions.
+// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
+// if (DEBUG_PERMISSIONS) {
+// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
+// + " for package " + pkg.getPackageName());
+// }
+// continue;
+// }
+
+ if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
+ if (DEBUG_PERMISSIONS) {
+ Log.i(TAG, "Denying runtime-only permission " + bp.getName()
+ + " for package " + pkg.getPackageName());
+ }
+ continue;
+ }
+
+ final String perm = bp.getName();
+ boolean allowedSig = false;
+ int grant = GRANT_DENIED;
+
+ // Keep track of app op permissions.
+ if (bp.isAppOp()) {
+ mSettings.addAppOpPackage(perm, pkg.getPackageName());
+ }
+
+ if (bp.isNormal()) {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if (bp.isRuntime()) {
+ if (origPermissions.hasInstallPermission(bp.getName())
+ || upgradedActivityRecognitionPermission != null) {
+ // Before Q we represented some runtime permissions as install permissions,
+ // in Q we cannot do this anymore. Hence upgrade them all.
+ grant = GRANT_UPGRADE;
+ } else {
+ // For modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
+ }
+ } else if (bp.isSignature()) {
+ // For all apps signature permissions are install time ones.
+ allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origPermissions);
+ if (allowedSig) {
+ grant = GRANT_INSTALL;
+ }
+ }
+
+ if (grant != GRANT_DENIED) {
+ if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
+ // If this is an existing, non-system package, then
+ // we can't add any new permissions to it. Runtime
+ // permissions can be added any time - they ad dynamic.
+ if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
+ // Except... if this is a permission that was added
+ // to the platform (note: need to only do this when
+ // updating the platform).
+ if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+ grant = GRANT_DENIED;
+ }
+ }
+ }
+ }
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ + pkg.getPackageName());
+ }
+
+ synchronized (mLock) {
+ if (grant != GRANT_DENIED) {
switch (grant) {
case GRANT_INSTALL: {
// Revoke this as runtime permission to handle the case of
// a runtime permission being downgraded to an install one.
// Also in permission review mode we keep dangerous permissions
// for legacy apps
- for (int userId : UserManagerService.getInstance().getUserIds()) {
+ for (int userId : currentUserIds) {
if (origPermissions.getRuntimePermissionState(
perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
@@ -3042,20 +3030,23 @@
}
}
}
+ }
- if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
- !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
- // This is the first that we have heard about this package, so the
- // permissions we have now selected are fixed until explicitly
- // changed.
- ps.setInstallPermissionsFixed(true);
- }
+ if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
+ !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
+ // This is the first that we have heard about this package, so the
+ // permissions we have now selected are fixed until explicitly
+ // changed.
+ ps.setInstallPermissionsFixed(true);
+ }
+ synchronized (mLock) {
updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
- updatedUserIds);
+ currentUserIds, updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
- permissionsState, pkg, newImplicitPermissions, updatedUserIds);
- updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, updatedUserIds);
+ permissionsState, pkg, newImplicitPermissions, currentUserIds, updatedUserIds);
+ updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, currentUserIds,
+ updatedUserIds);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -3076,23 +3067,19 @@
*
* @param ps The state of the permissions of the package
* @param pkg The package that is currently looked at
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds a list of user ids that needs to be amended if the permission state
* for a user is changed.
*
* @return The updated value of the {@code updatedUserIds} parameter
*/
- private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
- @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
- @NonNull int[] updatedUserIds) {
+ private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull PermissionsState ps,
+ @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
- int[] users = UserManagerService.getInstance().getUserIds();
- int numUsers = users.length;
- for (int i = 0; i < numUsers; i++) {
- int userId = users[i];
-
+ for (int userId : userIds) {
for (String permission : ps.getPermissions(userId)) {
if (!pkg.getImplicitPermissions().contains(permission)) {
if (!ps.hasInstallPermission(permission)) {
@@ -3188,16 +3175,17 @@
*
* @param pkg The package for which the permissions are updated
* @param replace If the app is being replaced
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds The ids of the users that already changed.
*
* @return The ids of the users that are changed
*/
- private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
- @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
+ private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(@NonNull AndroidPackage pkg,
+ boolean replace, @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
if (replace && pkg.isRequestLegacyExternalStorage() && (
pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
|| pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
- return UserManagerService.getInstance().getUserIds();
+ return userIds.clone();
}
return updatedUserIds;
@@ -3209,15 +3197,15 @@
* @param origPs The permission state of the package before the split
* @param ps The new permission state
* @param pkg The package the permission belongs to
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds List of users for which the permission state has already been changed
*
* @return List of users for which the permission state has been changed
*/
private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
- @NonNull PermissionsState origPs,
- @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
- @NonNull ArraySet<String> newImplicitPermissions,
- @NonNull int[] updatedUserIds) {
+ @NonNull PermissionsState origPs, @NonNull PermissionsState ps,
+ @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions,
+ @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
@@ -3251,11 +3239,7 @@
if (!ps.hasInstallPermission(newPerm)) {
BasePermission bp = mSettings.getPermissionLocked(newPerm);
- int[] users = UserManagerService.getInstance().getUserIds();
- int numUsers = users.length;
- for (int userNum = 0; userNum < numUsers; userNum++) {
- int userId = users[userNum];
-
+ for (int userId : userIds) {
if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
ps.updatePermissionFlags(bp, userId,
FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
@@ -3413,7 +3397,7 @@
return wlPermissions != null && wlPermissions.contains(perm);
}
- private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
+ private boolean shouldGrantSignaturePermission(String perm, AndroidPackage pkg,
PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) {
boolean oemPermission = bp.isOEM();
boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
@@ -4210,6 +4194,14 @@
// The target package is the source of the current permission
// Set to changed for either install or uninstall
changed = true;
+ if (needsUpdate == null) {
+ needsUpdate = new ArraySet<>(mSettings.mPermissions.size());
+ }
+ needsUpdate.add(bp);
+ }
+ }
+ if (needsUpdate != null) {
+ for (final BasePermission bp : needsUpdate) {
// If the target package is being uninstalled, we need to revoke this permission
// From all other packages
if (pkg == null || !hasPermission(pkg, bp.getName())) {
@@ -4239,16 +4231,9 @@
}
});
}
- it.remove();
+ mSettings.removePermissionLocked(bp.getName());
+ continue;
}
- if (needsUpdate == null) {
- needsUpdate = new ArraySet<>(mSettings.mPermissions.size());
- }
- needsUpdate.add(bp);
- }
- }
- if (needsUpdate != null) {
- for (final BasePermission bp : needsUpdate) {
final AndroidPackage sourcePkg =
mPackageManagerInt.getPackage(bp.getSourcePackageName());
final PackageSetting sourcePs =
@@ -4414,7 +4399,7 @@
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(
- callingUid, callingUserId, userId, requireFullPermission,
+ Binder.getCallingPid(), callingUid, callingUserId, userId, requireFullPermission,
requirePermissionWhenSameUser)) {
return;
}
@@ -4441,37 +4426,54 @@
private void enforceCrossUserOrProfilePermission(int callingUid, int userId,
boolean requireFullPermission, boolean checkShell,
String message) {
+ int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
- if (checkShell) {
- PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
- UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- final int callingUserId = UserHandle.getUserId(callingUid);
- if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
- /*requirePermissionWhenSameUser= */ false)) {
+
+ if (callingUserId == userId) {
return;
}
- final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
- if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
- mContext,
- android.Manifest.permission.INTERACT_ACROSS_PROFILES,
- PermissionChecker.PID_UNKNOWN,
- callingUid,
- mPackageManagerInt.getPackage(callingUid).getPackageName())
- == PermissionChecker.PERMISSION_GRANTED) {
+
+ // Prevent endless loop between when checking permission while checking a permission
+ if (callingPid == ActivityManagerService.MY_PID) {
return;
}
- String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
- message, requireFullPermission, isSameProfileGroup);
- Slog.w(TAG, errorMessage);
- throw new SecurityException(errorMessage);
+
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (checkShell) {
+ PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+ }
+ if (hasCrossUserPermission(callingPid, callingUid, callingUserId, userId,
+ requireFullPermission, /*requirePermissionWhenSameUser= */ false)) {
+ return;
+ }
+ final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+ if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+ mContext,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ PermissionChecker.PID_UNKNOWN,
+ callingUid,
+ mPackageManagerInt.getPackage(callingUid).getPackageName())
+ == PermissionChecker.PERMISSION_GRANTED) {
+ return;
+ }
+
+ String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
+ message, requireFullPermission, isSameProfileGroup);
+ Slog.w(TAG, errorMessage);
+ throw new SecurityException(errorMessage);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
- private boolean hasCrossUserPermission(
- int callingUid, int callingUserId, int userId, boolean requireFullPermission,
- boolean requirePermissionWhenSameUser) {
+ private boolean hasCrossUserPermission(int callingPid, int callingUid, int callingUserId,
+ int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
return true;
}
@@ -4479,15 +4481,11 @@
return true;
}
if (requireFullPermission) {
- return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ return mContext.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
}
- return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
- }
-
- private boolean hasPermission(String permission) {
- return mContext.checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
}
private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
@@ -4899,58 +4897,42 @@
@Override
public void setDialerAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
}
@Override
public void setLocationExtraPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
}
@Override
public void setLocationPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
}
@Override
public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
}
@Override
public void setSmsAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
}
@Override
public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
}
@Override
public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
}
@Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
}
@Override
@@ -4982,36 +4964,28 @@
@Override
public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+ packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultUseOpenWifiApp(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
+ packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultBrowser(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
@Override
public void onNewUserCreated(int userId) {
mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
- synchronized (mLock) {
- // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
- PermissionManagerService.this.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
- }
+ // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
+ PermissionManagerService.this.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL,
+ true, mDefaultPermissionCallback);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 355e243..eea8ac7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -88,12 +88,14 @@
}
public void addAppOpPackage(String permName, String packageName) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName);
- if (pkgs == null) {
- pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(permName, pkgs);
+ synchronized (mLock) {
+ ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName);
+ if (pkgs == null) {
+ pkgs = new ArraySet<>();
+ mAppOpPermissionPackages.put(permName, pkgs);
+ }
+ pkgs.add(packageName);
}
- pkgs.add(packageName);
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index c0d71ac..65dc320 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,14 +18,6 @@
]
},
{
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
- }
- ]
- },
- {
"name": "CtsPermission2TestCases",
"options": [
{
@@ -37,6 +29,17 @@
]
},
{
+ "name": "CtsPermissionHostTestCases"
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
+ }
+ ]
+ },
+ {
"name": "CtsStatsdHostTestCases",
"options": [
{
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 37f088b..4d48a2e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -67,6 +67,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
@@ -347,7 +348,11 @@
}
@Override
- public void onStartUser(@UserIdInt int userId) {
+ public void onUserStarting(@NonNull TargetUser user) {
+ onStartUser(user.getUserIdentifier());
+ }
+
+ private void onStartUser(@UserIdInt int userId) {
if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")");
if (isStarted(userId)) {
@@ -373,11 +378,11 @@
}
@Override
- public void onStopUser(@UserIdInt int userId) {
- if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + userId + ")");
+ public void onUserStopping(@NonNull TargetUser user) {
+ if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")");
synchronized (mLock) {
- mIsStarted.delete(userId);
+ mIsStarted.delete(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 4c4680b..f9a49c9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -493,9 +493,6 @@
private boolean mProximityPositive;
// Screen brightness setting limits.
- private float mScreenBrightnessSettingMinimum;
- private float mScreenBrightnessSettingMaximum;
- private float mScreenBrightnessSettingDefault;
public final float mScreenBrightnessMinimum;
public final float mScreenBrightnessMaximum;
public final float mScreenBrightnessDefault;
@@ -1030,14 +1027,6 @@
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mScreenBrightnessSettingMinimum = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
- mScreenBrightnessSettingMaximum = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
- mScreenBrightnessSettingDefault = pm.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT);
-
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
// The notifier runs on the system server's main looper so as not to interfere
@@ -2818,7 +2807,7 @@
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessSettingDefault;
+ screenBrightnessOverride = mScreenBrightnessDefault;
} else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
autoBrightness = false;
screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
@@ -3208,6 +3197,7 @@
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
+ // No check point from ShutdownCheckPoints will be dumped at this state.
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
@@ -3868,9 +3858,9 @@
pw.println(" mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
pw.println(" mDozeScreenBrightnessOverrideFromDreamManager="
+ mDozeScreenBrightnessOverrideFromDreamManager);
- pw.println(" mScreenBrightnessSettingMinimumFloat=" + mScreenBrightnessSettingMinimum);
- pw.println(" mScreenBrightnessSettingMaximumFloat=" + mScreenBrightnessSettingMaximum);
- pw.println(" mScreenBrightnessSettingDefaultFloat=" + mScreenBrightnessSettingDefault);
+ pw.println(" mScreenBrightnessMinimum=" + mScreenBrightnessMinimum);
+ pw.println(" mScreenBrightnessMaximum=" + mScreenBrightnessMaximum);
+ pw.println(" mScreenBrightnessDefault=" + mScreenBrightnessDefault);
pw.println(" mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled);
pw.println(" mIsVrModeEnabled=" + mIsVrModeEnabled);
pw.println(" mForegroundProfile=" + mForegroundProfile);
@@ -4227,15 +4217,15 @@
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
.SETTING_MINIMUM_FLOAT,
- mScreenBrightnessSettingMinimum);
+ mScreenBrightnessMinimum);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
.SETTING_MAXIMUM_FLOAT,
- mScreenBrightnessSettingMaximum);
+ mScreenBrightnessMaximum);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
.SETTING_DEFAULT_FLOAT,
- mScreenBrightnessSettingDefault);
+ mScreenBrightnessDefault);
proto.end(screenBrightnessSettingLimitsToken);
proto.write(
@@ -5114,6 +5104,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
@@ -5132,10 +5123,11 @@
public void rebootSafeMode(boolean confirm, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+ String reason = PowerManager.REBOOT_SAFE_MODE;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm,
- PowerManager.REBOOT_SAFE_MODE, wait);
+ shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5151,6 +5143,7 @@
public void shutdown(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
diff --git a/services/core/java/com/android/server/power/ShutdownCheckPoints.java b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
index e6d0ddd..05ee7df 100644
--- a/services/core/java/com/android/server/power/ShutdownCheckPoints.java
+++ b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
@@ -90,18 +90,19 @@
}
/** Records the stack trace of this {@link Thread} as a shutdown check point. */
- public static void recordCheckPoint() {
- INSTANCE.recordCheckPointInternal();
+ public static void recordCheckPoint(@Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(reason);
}
/** Records the pid of the caller process as a shutdown check point. */
- public static void recordCheckPoint(int callerProcessId) {
- INSTANCE.recordCheckPointInternal(callerProcessId);
+ public static void recordCheckPoint(int callerProcessId, @Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(callerProcessId, reason);
}
/** Records the {@link android.content.Intent} name and package as a shutdown check point. */
- public static void recordCheckPoint(String intentName, String packageName) {
- INSTANCE.recordCheckPointInternal(intentName, packageName);
+ public static void recordCheckPoint(
+ String intentName, String packageName, @Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(intentName, packageName, reason);
}
/** Serializes the recorded check points and writes them to given {@code printWriter}. */
@@ -119,24 +120,24 @@
}
@VisibleForTesting
- void recordCheckPointInternal() {
- recordCheckPointInternal(new SystemServerCheckPoint(mInjector));
+ void recordCheckPointInternal(@Nullable String reason) {
+ recordCheckPointInternal(new SystemServerCheckPoint(mInjector, reason));
Slog.v(TAG, "System server shutdown checkpoint recorded");
}
@VisibleForTesting
- void recordCheckPointInternal(int callerProcessId) {
+ void recordCheckPointInternal(int callerProcessId, @Nullable String reason) {
recordCheckPointInternal(callerProcessId == Process.myPid()
- ? new SystemServerCheckPoint(mInjector)
- : new BinderCheckPoint(mInjector, callerProcessId));
+ ? new SystemServerCheckPoint(mInjector, reason)
+ : new BinderCheckPoint(mInjector, callerProcessId, reason));
Slog.v(TAG, "Binder shutdown checkpoint recorded with pid=" + callerProcessId);
}
@VisibleForTesting
- void recordCheckPointInternal(String intentName, String packageName) {
+ void recordCheckPointInternal(String intentName, String packageName, @Nullable String reason) {
recordCheckPointInternal("android".equals(packageName)
- ? new SystemServerCheckPoint(mInjector)
- : new IntentCheckPoint(mInjector, intentName, packageName));
+ ? new SystemServerCheckPoint(mInjector, reason)
+ : new IntentCheckPoint(mInjector, intentName, packageName, reason));
Slog.v(TAG, String.format("Shutdown intent checkpoint recorded intent=%s from package=%s",
intentName, packageName));
}
@@ -182,14 +183,20 @@
private abstract static class CheckPoint {
private final long mTimestamp;
+ @Nullable private final String mReason;
- CheckPoint(Injector injector) {
+ CheckPoint(Injector injector, @Nullable String reason) {
mTimestamp = injector.currentTimeMillis();
+ mReason = reason;
}
final void dump(PrintWriter printWriter) {
printWriter.print("Shutdown request from ");
printWriter.print(getOrigin());
+ if (mReason != null) {
+ printWriter.print(" for reason ");
+ printWriter.print(mReason);
+ }
printWriter.print(" at ");
printWriter.print(DATE_FORMAT.format(new Date(mTimestamp)));
printWriter.println(" (epoch=" + mTimestamp + ")");
@@ -206,8 +213,8 @@
private final StackTraceElement[] mStackTraceElements;
- SystemServerCheckPoint(Injector injector) {
- super(injector);
+ SystemServerCheckPoint(Injector injector, @Nullable String reason) {
+ super(injector, reason);
mStackTraceElements = Thread.currentThread().getStackTrace();
}
@@ -263,8 +270,8 @@
private final int mCallerProcessId;
private final IActivityManager mActivityManager;
- BinderCheckPoint(Injector injector, int callerProcessId) {
- super(injector);
+ BinderCheckPoint(Injector injector, int callerProcessId, @Nullable String reason) {
+ super(injector, reason);
mCallerProcessId = callerProcessId;
mActivityManager = injector.activityManager();
}
@@ -307,8 +314,9 @@
private final String mIntentName;
private final String mPackageName;
- IntentCheckPoint(Injector injector, String intentName, String packageName) {
- super(injector);
+ IntentCheckPoint(
+ Injector injector, String intentName, String packageName, @Nullable String reason) {
+ super(injector, reason);
mIntentName = intentName;
mPackageName = packageName;
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 2621d8b..e94575c 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -65,7 +65,7 @@
private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
// maximum time we wait for the shutdown broadcast before going on.
private static final int MAX_BROADCAST_TIME = 10 * 1000;
- private static final int MAX_CHECK_POINTS_DUMP_WAIT_TIME = 20 * 1000;
+ private static final int MAX_CHECK_POINTS_DUMP_WAIT_TIME = 10 * 1000;
private static final int MAX_RADIO_WAIT_TIME = 12 * 1000;
private static final int MAX_UNCRYPT_WAIT_TIME = 15 * 60 * 1000;
// constants for progress bar. the values are roughly estimated based on timeout.
@@ -165,6 +165,10 @@
}
}
+ // Add checkpoint for this shutdown attempt. The user might still cancel the dialog, but
+ // this point preserves the system trace of the trigger point of the ShutdownThread.
+ ShutdownCheckPoints.recordCheckPoint(/* reason= */ null);
+
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
final int resourceId = mRebootSafeMode
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 392792d..a291cef 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -34,14 +34,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
-import android.database.CursorWindow;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
@@ -74,6 +71,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.ByteArrayOutputStream;
@@ -217,8 +215,8 @@
}
@Override
- public void onStartUser(@UserIdInt int userId) {
- maybeGrantDefaultRolesSync(userId);
+ public void onUserStarting(@NonNull TargetUser user) {
+ maybeGrantDefaultRolesSync(user.getUserIdentifier());
}
@MainThread
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index ce1156b..04a5ca5 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -16,10 +16,12 @@
package com.android.server.rollback;
+import android.annotation.NonNull;
import android.content.Context;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
/**
* Service that manages APK level rollbacks. Publishes
@@ -43,8 +45,8 @@
}
@Override
- public void onUserUnlocking(TargetUser user) {
- mService.onUnlockUser(user.getUserHandle().getIdentifier());
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.onUnlockUser(user.getUserIdentifier());
}
@Override
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index fea68d3..7091c47 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -16,9 +16,7 @@
package com.android.server.search;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
+import android.annotation.NonNull;
import android.app.ISearchManager;
import android.app.SearchManager;
import android.app.SearchableInfo;
@@ -26,18 +24,14 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.voice.VoiceInteractionService;
import android.util.Log;
import android.util.SparseArray;
@@ -48,6 +42,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.FileDescriptor;
@@ -76,18 +71,13 @@
}
@Override
- public void onUnlockUser(final int userId) {
- mService.mHandler.post(new Runnable() {
- @Override
- public void run() {
- mService.onUnlockUser(userId);
- }
- });
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.mHandler.post(() -> mService.onUnlockUser(user.getUserIdentifier()));
}
@Override
- public void onCleanupUser(int userHandle) {
- mService.onCleanupUser(userHandle);
+ public void onUserStopped(@NonNull TargetUser user) {
+ mService.onCleanupUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 7c8c494..4349ca4 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -26,6 +26,7 @@
import static android.os.Process.SYSTEM_UID;
import android.Manifest.permission;
+import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.app.slice.ISliceManager;
import android.app.slice.SliceSpec;
@@ -59,10 +60,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
-import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -615,13 +616,13 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- mService.onUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.onUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mService.onStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.onStopUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 93ea5e3..9bc8afa 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -67,6 +67,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.notification.NotificationDelegate;
import com.android.server.policy.GlobalActionsProvider;
+import com.android.server.power.ShutdownCheckPoints;
import com.android.server.power.ShutdownThread;
import java.io.FileDescriptor;
@@ -1182,13 +1183,14 @@
@Override
public void shutdown() {
enforceStatusBarService();
+ String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
// ShutdownThread displays UI, so give it a UI context.
mHandler.post(() ->
- ShutdownThread.shutdown(getUiContext(),
- PowerManager.SHUTDOWN_USER_REQUESTED, false));
+ ShutdownThread.shutdown(getUiContext(), reason, false));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1200,6 +1202,10 @@
@Override
public void reboot(boolean safeMode) {
enforceStatusBarService();
+ String reason = safeMode
+ ? PowerManager.REBOOT_SAFE_MODE
+ : PowerManager.SHUTDOWN_USER_REQUESTED;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
@@ -1208,8 +1214,7 @@
if (safeMode) {
ShutdownThread.rebootSafeMode(getUiContext(), true);
} else {
- ShutdownThread.reboot(getUiContext(),
- PowerManager.SHUTDOWN_USER_REQUESTED, false);
+ ShutdownThread.reboot(getUiContext(), reason, false);
}
});
} finally {
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 361a506..1c29c69 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
@@ -64,9 +65,6 @@
private static final String TAG = "StorageUserConnection";
private static final int DEFAULT_REMOTE_TIMEOUT_SECONDS = 20;
- // TODO(b/161702661): Workaround for demo user to have shorter timeout.
- // This allows the DevicePolicyManagerService#enableSystemApp call to succeed without ANR.
- private static final int DEMO_USER_REMOTE_TIMEOUT_SECONDS = 5;
private final Object mLock = new Object();
private final Context mContext;
@@ -75,6 +73,7 @@
private final ActiveConnection mActiveConnection = new ActiveConnection();
private final boolean mIsDemoUser;
@GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+ @GuardedBy("mLock") @Nullable private HandlerThread mHandlerThread;
public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
mContext = Objects.requireNonNull(context);
@@ -82,6 +81,10 @@
mSessionController = controller;
mIsDemoUser = LocalServices.getService(UserManagerInternal.class)
.getUserInfo(userId).isDemo();
+ if (mIsDemoUser) {
+ mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
+ mHandlerThread.start();
+ }
}
/**
@@ -188,6 +191,9 @@
*/
public void close() {
mActiveConnection.close();
+ if (mIsDemoUser) {
+ mHandlerThread.quit();
+ }
}
/** Returns all created sessions. */
@@ -207,8 +213,7 @@
private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
try {
- if (!latch.await(mIsDemoUser ? DEMO_USER_REMOTE_TIMEOUT_SECONDS
- : DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+ if (!latch.await(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
// TODO(b/140025078): Call ActivityManager ANR API?
Slog.wtf(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
throw new TimeoutException("Latch wait for " + reason + " elapsed");
@@ -424,15 +429,32 @@
};
Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
- if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.of(mUserId))) {
- Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
- return mLatch;
+ if (mIsDemoUser) {
+ // Schedule on a worker thread for demo user to avoid deadlock
+ if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ mHandlerThread.getThreadHandler(),
+ UserHandle.of(mUserId))) {
+ Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+ return mLatch;
+ } else {
+ mIsConnecting = false;
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
+ }
} else {
- mIsConnecting = false;
- throw new ExternalStorageServiceException(
- "Failed to bind to the ExternalStorageService for user " + mUserId);
+ if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.of(mUserId))) {
+ Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+ return mLatch;
+ } else {
+ mIsConnecting = false;
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 1707d95..363e86d 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -66,6 +66,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -118,14 +119,14 @@
}
@Override
- public void onStartUser(int userId) {
- processAnyPendingWork(userId);
+ public void onUserStarting(@NonNull TargetUser user) {
+ processAnyPendingWork(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userId) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
// Rebind if we failed earlier due to locked encrypted user
- processAnyPendingWork(userId);
+ processAnyPendingWork(user.getUserIdentifier());
}
private void processAnyPendingWork(int userId) {
@@ -135,7 +136,9 @@
}
@Override
- public void onStopUser(int userId) {
+ public void onUserStopping(@NonNull TargetUser user) {
+ int userId = user.getUserIdentifier();
+
synchronized (mManagerService.mLock) {
UserState userState = mManagerService.peekUserStateLocked(userId);
if (userState != null) {
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index e0bac93..f39067b 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -58,6 +58,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParserException;
@@ -287,21 +288,21 @@
}
@Override
- public void onStopUser(@UserIdInt int userHandle) {
+ public void onUserStopping(@NonNull TargetUser user) {
if (DBG) {
- Slog.d(TAG, "onStopUser userId: " + userHandle);
+ Slog.d(TAG, "onStopUser user: " + user);
}
- mService.onStopUser(userHandle);
+ mService.onStopUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(@UserIdInt int userHandle) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
if(DBG) {
- Slog.d(TAG, "onUnlockUser userId: " + userHandle);
+ Slog.d(TAG, "onUnlockUser userId: " + user);
}
// Called on the system server's main looper thread.
// TODO: Dispatch this to a worker thread as needed.
- mService.onUnlockUser(userHandle);
+ mService.onUnlockUser(user.getUserIdentifier());
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index fd3c1f9..6adff0d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -17,6 +17,8 @@
package com.android.server.trust;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -71,6 +73,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1042,28 +1045,28 @@
// User lifecycle
@Override
- public void onStartUser(int userId) {
- mHandler.obtainMessage(MSG_START_USER, userId, 0, null).sendToTarget();
+ public void onUserStarting(@NonNull TargetUser user) {
+ mHandler.obtainMessage(MSG_START_USER, user.getUserIdentifier(), 0, null).sendToTarget();
}
@Override
- public void onCleanupUser(int userId) {
- mHandler.obtainMessage(MSG_CLEANUP_USER, userId, 0, null).sendToTarget();
+ public void onUserStopped(@NonNull TargetUser user) {
+ mHandler.obtainMessage(MSG_CLEANUP_USER, user.getUserIdentifier(), 0, null).sendToTarget();
}
@Override
- public void onSwitchUser(int userId) {
- mHandler.obtainMessage(MSG_SWITCH_USER, userId, 0, null).sendToTarget();
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mHandler.obtainMessage(MSG_SWITCH_USER, to.getUserIdentifier(), 0, null).sendToTarget();
}
@Override
- public void onUnlockUser(int userId) {
- mHandler.obtainMessage(MSG_UNLOCK_USER, userId, 0, null).sendToTarget();
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mHandler.obtainMessage(MSG_UNLOCK_USER, user.getUserIdentifier(), 0, null).sendToTarget();
}
@Override
- public void onStopUser(@UserIdInt int userId) {
- mHandler.obtainMessage(MSG_STOP_USER, userId, 0, null).sendToTarget();
+ public void onUserStopping(@NonNull TargetUser user) {
+ mHandler.obtainMessage(MSG_STOP_USER, user.getUserIdentifier(), 0, null).sendToTarget();
}
// Plumbing
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 323ac7b..b3ec849 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -20,6 +20,7 @@
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
@@ -83,6 +84,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import java.io.File;
import java.io.FileDescriptor;
@@ -165,10 +167,10 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- if (DEBUG) Slog.d(TAG, "onUnlockUser(userHandle=" + userHandle + ")");
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ if (DEBUG) Slog.d(TAG, "onUnlockUser(user=" + user + ")");
synchronized (mLock) {
- if (mCurrentUserId != userHandle) {
+ if (mCurrentUserId != user.getUserIdentifier()) {
return;
}
buildTvInputListLocked(mCurrentUserId, null);
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 88a60dd..47ab127 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.icu.impl.CalendarAstronomer;
import android.icu.util.Calendar;
import android.location.Location;
import android.location.LocationListener;
@@ -38,6 +37,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
+import com.ibm.icu.impl.CalendarAstronomer;
+
import java.util.Objects;
/**
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 45689ce..ae873e2 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -65,6 +66,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import com.android.server.utils.ManagedApplicationService.LogEvent;
@@ -817,14 +819,14 @@
}
@Override
- public void onStartUser(int userHandle) {
+ public void onUserStarting(@NonNull TargetUser user) {
synchronized (mLock) {
mComponentObserver.onUsersChanged();
}
}
@Override
- public void onSwitchUser(int userHandle) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
FgThread.getHandler().post(() -> {
synchronized (mLock) {
mComponentObserver.onUsersChanged();
@@ -834,7 +836,7 @@
}
@Override
- public void onStopUser(int userHandle) {
+ public void onUserStopping(@NonNull TargetUser user) {
synchronized (mLock) {
mComponentObserver.onUsersChanged();
}
@@ -842,7 +844,7 @@
}
@Override
- public void onCleanupUser(int userHandle) {
+ public void onUserStopped(@NonNull TargetUser user) {
synchronized (mLock) {
mComponentObserver.onUsersChanged();
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 90f87b1..2f695c6 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -105,6 +105,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.WindowManagerInternal;
@@ -166,9 +167,9 @@
}
@Override
- public void onUnlockUser(int userHandle) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
if (mService != null) {
- mService.onUnlockUser(userHandle);
+ mService.onUnlockUser(user.getUserIdentifier());
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dd67b3d2..b72ff2d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2865,7 +2865,7 @@
if (hasProcess()) {
if (removeFromApp) {
- app.removeActivity(this);
+ app.removeActivity(this, true /* keepAssociation */);
if (!app.hasActivities()) {
mAtmService.clearHeavyWeightProcessIfEquals(app);
// Update any services we are bound to that might care about whether
@@ -2914,7 +2914,7 @@
setState(DESTROYED,
"destroyActivityLocked. not finishing or skipping destroy");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this);
- app = null;
+ detachFromProcess();
}
} else {
// Remove this record from the history.
@@ -2963,13 +2963,20 @@
}
setState(DESTROYED, "removeFromHistory");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
- app = null;
+ detachFromProcess();
removeAppTokenFromDisplay();
cleanUpActivityServices();
removeUriPermissionsLocked();
}
+ void detachFromProcess() {
+ if (app != null) {
+ app.removeActivity(this, false /* keepAssociation */);
+ }
+ app = null;
+ }
+
void makeFinishingLocked() {
if (finishing) {
return;
@@ -3019,7 +3026,7 @@
if (setState) {
setState(DESTROYED, "cleanUp");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + this);
- app = null;
+ detachFromProcess();
}
// Inform supervisor the activity has been removed.
@@ -3160,6 +3167,64 @@
mServiceConnectionsHolder = null;
}
+ /**
+ * Detach this activity from process and clear the references to it. If the activity is
+ * finishing or has no saved state or crashed many times, it will also be removed from history.
+ */
+ void handleAppDied() {
+ final boolean remove;
+ if ((mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
+ || mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
+ && launchCount < 3 && !finishing) {
+ // If the process crashed during a resize, always try to relaunch it, unless it has
+ // failed more than twice. Skip activities that's already finishing cleanly by itself.
+ remove = false;
+ } else if ((!mHaveState && !stateNotNeeded
+ && !isState(ActivityState.RESTARTING_PROCESS)) || finishing) {
+ // Don't currently have state for the activity, or it is finishing -- always remove it.
+ remove = true;
+ } else if (!mVisibleRequested && launchCount > 2
+ && lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+ // We have launched this activity too many times since it was able to run, so give up
+ // and remove it. (Note if the activity is visible, we don't remove the record. We leave
+ // the dead window on the screen but the process will not be restarted unless user
+ // explicitly tap on it.)
+ remove = true;
+ } else {
+ // The process may be gone, but the activity lives on!
+ remove = false;
+ }
+ if (remove) {
+ if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
+ Slog.i(TAG_ADD_REMOVE, "Removing activity " + this
+ + " hasSavedState=" + mHaveState + " stateNotNeeded=" + stateNotNeeded
+ + " finishing=" + finishing + " state=" + mState
+ + " callers=" + Debug.getCallers(5));
+ }
+ if (!finishing || (app != null && app.isRemoved())) {
+ Slog.w(TAG, "Force removing " + this + ": app died, no saved state");
+ EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
+ task != null ? task.mTaskId : -1, shortComponentName,
+ "proc died without state saved");
+ }
+ } else {
+ // We have the current state for this activity, so it can be restarted later
+ // when needed.
+ if (DEBUG_APP) {
+ Slog.v(TAG_APP, "Keeping entry during removeHistory for activity " + this);
+ }
+ // Set nowVisible to previous visible state. If the app was visible while it died, we
+ // leave the dead window on screen so it's basically visible. This is needed when user
+ // later tap on the dead window, we need to stop other apps when user transfers focus
+ // to the restarted activity.
+ nowVisible = mVisibleRequested;
+ }
+ cleanUp(true /* cleanServices */, true /* setState */);
+ if (remove) {
+ removeFromHistory("appDied");
+ }
+ }
+
@Override
void removeImmediately() {
onRemovedFromDisplay();
@@ -4114,6 +4179,12 @@
// Now that the app is going invisible, we can remove it. It will be restarted
// if made visible again.
removeDeadWindows();
+ // If this activity is about to finish/stopped and now becomes invisible, remove it
+ // from the unknownApp list in case the activity does not want to draw anything, which
+ // keep the user waiting for the next transition to start.
+ if (finishing || isState(STOPPED)) {
+ displayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+ }
} else {
if (!appTransition.isTransitionSet()
&& appTransition.isReady()) {
@@ -5919,10 +5990,8 @@
// stack, i.e. the hierarchy of the surfaces is unchanged.
if (inPinnedWindowingMode()) {
return getStack().getSurfaceControl();
- } else if (WindowManagerService.sHierarchicalAnimations) {
- return super.getAnimationLeashParent();
} else {
- return getAppAnimationLayer();
+ return super.getAnimationLeashParent();
}
}
@@ -6010,11 +6079,6 @@
mAnimationBoundsLayer = createAnimationBoundsLayer(t);
// Crop to stack bounds.
- if (!WindowManagerService.sHierarchicalAnimations) {
- // For Hierarchical animation, we don't need to set window crop since the leash
- // surface size has already same as the animating container.
- t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
- }
t.setLayer(leash, 0);
t.setLayer(mAnimationBoundsLayer, getAnimationLayer());
@@ -7568,6 +7632,11 @@
}
@Override
+ boolean canCustomizeAppTransition() {
+ return true;
+ }
+
+ @Override
public String toString() {
if (stringName != null) {
return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 04b1edc..ed1ea35 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -891,7 +891,7 @@
// This is the first time we failed -- restart process and
// retry.
r.launchFailed = true;
- proc.removeActivity(r);
+ proc.removeActivity(r, true /* keepAssociation */);
throw e;
}
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e84f040..f7cb014 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -118,6 +118,7 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
+import com.android.server.power.ShutdownCheckPoints;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
@@ -647,6 +648,19 @@
mRequest.resolveActivity(mSupervisor);
}
+ // Add checkpoint for this shutdown or reboot attempt, so we can record the original
+ // intent action and package name.
+ if (mRequest.intent != null) {
+ String intentAction = mRequest.intent.getAction();
+ String callingPackage = mRequest.callingPackage;
+ if (intentAction != null && callingPackage != null
+ && (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)
+ || Intent.ACTION_SHUTDOWN.equals(intentAction)
+ || Intent.ACTION_REBOOT.equals(intentAction))) {
+ ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);
+ }
+ }
+
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c4af3e2..5534b8c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -254,6 +254,7 @@
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.SystemServiceManager;
import com.android.server.UiThread;
import com.android.server.Watchdog;
@@ -1027,16 +1028,17 @@
}
@Override
- public void onUnlockUser(int userId) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
synchronized (mService.getGlobalLock()) {
- mService.mStackSupervisor.onUserUnlocked(userId);
+ mService.mStackSupervisor.onUserUnlocked(user.getUserIdentifier());
}
}
@Override
- public void onCleanupUser(int userId) {
+ public void onUserStopped(@NonNull TargetUser user) {
synchronized (mService.getGlobalLock()) {
- mService.mStackSupervisor.mLaunchParamsPersister.onCleanupUser(userId);
+ mService.mStackSupervisor.mLaunchParamsPersister
+ .onCleanupUser(user.getUserIdentifier());
}
}
@@ -6789,11 +6791,14 @@
public void handleAppDied(WindowProcessController wpc, boolean restarting,
Runnable finishInstrumentationCallback) {
synchronized (mGlobalLockWithoutBoost) {
- // Remove this application's activities from active lists.
- boolean hasVisibleActivities = mRootWindowContainer.handleAppDied(wpc);
-
- wpc.clearRecentTasks();
- wpc.clearActivities();
+ mStackSupervisor.beginDeferResume();
+ final boolean hasVisibleActivities;
+ try {
+ // Remove this application's activities from active lists.
+ hasVisibleActivities = wpc.handleAppDied();
+ } finally {
+ mStackSupervisor.endDeferResume();
+ }
if (wpc.isInstrumenting()) {
finishInstrumentationCallback.run();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 3abc54f..11a468b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -203,6 +203,7 @@
private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
+ private boolean mNextAppTransitionOverrideRequested;
// These are the possible states for the enter/exit activities during a thumbnail transition
private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
@@ -337,6 +338,11 @@
mNextAppTransitionFlags |= flags;
setLastAppTransition(TRANSIT_UNSET, null, null, null);
updateBooster();
+ if (isTransitionSet()) {
+ removeAppTransitionTimeoutCallbacks();
+ mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
+ APP_TRANSITION_TIMEOUT_MS);
+ }
}
void setLastAppTransition(int transit, ActivityRecord openingApp, ActivityRecord closingApp,
@@ -454,6 +460,7 @@
void clear() {
mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
+ mNextAppTransitionOverrideRequested = false;
mNextAppTransitionPackage = null;
mNextAppTransitionAnimationsSpecs.clear();
mRemoteAnimationController = null;
@@ -1574,6 +1581,7 @@
*/
boolean canSkipFirstFrame() {
return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
+ && !mNextAppTransitionOverrideRequested
&& mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
&& mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
&& mNextAppTransition != TRANSIT_KEYGUARD_GOING_AWAY;
@@ -1608,6 +1616,11 @@
int orientation, Rect frame, Rect displayFrame, Rect insets,
@Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
boolean freeform, WindowContainer container) {
+
+ if (mNextAppTransitionOverrideRequested && container.canCustomizeAppTransition()) {
+ mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+ }
+
Animation a;
if (isKeyguardGoingAwayTransit(transit) && enter) {
a = loadKeyguardExitAnimation(transit);
@@ -1648,7 +1661,6 @@
"applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
+ "isEntrance=%b Callers=%s",
a, appTransitionToString(transit), enter, Debug.getCallers(3));
- setAppTransitionFinishedCallbackIfNeeded(a);
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1775,6 +1787,7 @@
a, animAttr, appTransitionToString(transit), enter,
Debug.getCallers(3));
}
+ setAppTransitionFinishedCallbackIfNeeded(a);
return a;
}
@@ -1816,7 +1829,7 @@
IRemoteCallback startedCallback, IRemoteCallback endedCallback) {
if (canOverridePendingAppTransition()) {
clear();
- mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
+ mNextAppTransitionOverrideRequested = true;
mNextAppTransitionPackage = packageName;
mNextAppTransitionEnter = enterAnim;
mNextAppTransitionExit = exitAnim;
@@ -2134,15 +2147,16 @@
pw.print(prefix); pw.print("mNextAppTransitionType=");
pw.println(transitTypeToString());
}
+ if (mNextAppTransitionOverrideRequested
+ || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
+ pw.print(prefix); pw.print("mNextAppTransitionPackage=");
+ pw.println(mNextAppTransitionPackage);
+ pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
+ pw.print(Integer.toHexString(mNextAppTransitionEnter));
+ pw.print(" mNextAppTransitionExit=0x");
+ pw.println(Integer.toHexString(mNextAppTransitionExit));
+ }
switch (mNextAppTransitionType) {
- case NEXT_TRANSIT_TYPE_CUSTOM:
- pw.print(prefix); pw.print("mNextAppTransitionPackage=");
- pw.println(mNextAppTransitionPackage);
- pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
- pw.print(Integer.toHexString(mNextAppTransitionEnter));
- pw.print(" mNextAppTransitionExit=0x");
- pw.println(Integer.toHexString(mNextAppTransitionExit));
- break;
case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
pw.print(prefix); pw.print("mNextAppTransitionPackage=");
pw.println(mNextAppTransitionPackage);
@@ -2229,12 +2243,7 @@
setAppTransition(transit, flags);
}
}
- boolean prepared = prepare();
- if (isTransitionSet()) {
- removeAppTransitionTimeoutCallbacks();
- mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable, APP_TRANSITION_TIMEOUT_MS);
- }
- return prepared;
+ return prepare();
}
/**
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d60d098..5720e9b 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -411,10 +411,6 @@
}
}
- if (!WindowManagerService.sHierarchicalAnimations) {
- return new ArraySet<>(candidates);
- }
-
final ArraySet<ActivityRecord> otherApps = visible ? closingApps : openingApps;
// Ancestors of closing apps while finding animation targets for opening apps, or ancestors
// of opening apps while finding animation targets for closing apps.
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 0d8e882..13033a6 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -93,9 +93,17 @@
private final Rect mTmpRect = new Rect();
static final int BOUNDS_CHANGE_NONE = 0;
- // Return value from {@link setBounds} indicating the position of the override bounds changed.
+
+ /**
+ * Return value from {@link #setBounds(Rect)} indicating the position of the override bounds
+ * changed.
+ */
static final int BOUNDS_CHANGE_POSITION = 1;
- // Return value from {@link setBounds} indicating the size of the override bounds changed.
+
+ /**
+ * Return value from {@link #setBounds(Rect)} indicating the size of the override bounds
+ * changed.
+ */
static final int BOUNDS_CHANGE_SIZE = 1 << 1;
/**
@@ -226,6 +234,11 @@
return equivalentBounds(getRequestedOverrideBounds(), bounds);
}
+ /** Similar to {@link #equivalentRequestedOverrideBounds(Rect)}, but compares max bounds. */
+ public boolean equivalentRequestedOverrideMaxBounds(Rect bounds) {
+ return equivalentBounds(getRequestedOverrideMaxBounds(), bounds);
+ }
+
/**
* Returns whether the two bounds are equal to each other or are a combination of null or empty.
*/
@@ -238,7 +251,6 @@
/**
* Returns the effective bounds of this container, inheriting the first non-empty bounds set in
* its ancestral hierarchy, including itself.
- * @return
*/
public Rect getBounds() {
mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
@@ -249,6 +261,12 @@
outBounds.set(getBounds());
}
+ /** Similar to {@link #getBounds()}, but reports the max bounds. */
+ public Rect getMaxBounds() {
+ mReturnBounds.set(getConfiguration().windowConfiguration.getMaxBounds());
+ return mReturnBounds;
+ }
+
/**
* Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
*/
@@ -273,6 +291,13 @@
return mReturnBounds;
}
+ /** Similar to {@link #getRequestedOverrideBounds()}, but returns the max bounds. */
+ public Rect getRequestedOverrideMaxBounds() {
+ mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getMaxBounds());
+
+ return mReturnBounds;
+ }
+
/**
* Returns {@code true} if the {@link WindowConfiguration} in the requested override
* {@link Configuration} specifies bounds.
@@ -283,7 +308,7 @@
/**
* Sets the passed in {@link Rect} to the current bounds.
- * @see {@link #getRequestedOverrideBounds()}.
+ * @see #getRequestedOverrideBounds()
*/
public void getRequestedOverrideBounds(Rect outBounds) {
outBounds.set(getRequestedOverrideBounds());
@@ -295,19 +320,25 @@
* {@link #getRequestedOverrideBounds()}. If
* an empty {@link Rect} or null is specified, this container will be considered to match its
* parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
+ *
* @param bounds The bounds defining the container size.
+ *
* @return a bitmask representing the types of changes made to the bounds.
*/
public int setBounds(Rect bounds) {
int boundsChange = diffRequestedOverrideBounds(bounds);
+ final boolean overrideMaxBounds = providesMaxBounds()
+ && diffRequestedOverrideMaxBounds(bounds) != BOUNDS_CHANGE_NONE;
- if (boundsChange == BOUNDS_CHANGE_NONE) {
+ if (boundsChange == BOUNDS_CHANGE_NONE && !overrideMaxBounds) {
return boundsChange;
}
-
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
+ if (overrideMaxBounds) {
+ mRequestsTmpConfig.windowConfiguration.setMaxBounds(bounds);
+ }
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
return boundsChange;
@@ -318,6 +349,40 @@
return setBounds(mTmpRect);
}
+ /**
+ * Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to
+ * its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise.
+ * <p>
+ * The maximum bounds is how large a window can be expanded. Currently only
+ * {@link DisplayContent} and {@link DisplayArea} effect this property.
+ * </p>
+ */
+ protected boolean providesMaxBounds() {
+ return false;
+ }
+
+ int diffRequestedOverrideMaxBounds(Rect bounds) {
+ if (equivalentRequestedOverrideMaxBounds(bounds)) {
+ return BOUNDS_CHANGE_NONE;
+ }
+
+ int boundsChange = BOUNDS_CHANGE_NONE;
+
+ final Rect existingBounds = getRequestedOverrideMaxBounds();
+
+ if (bounds == null || existingBounds.left != bounds.left
+ || existingBounds.top != bounds.top) {
+ boundsChange |= BOUNDS_CHANGE_POSITION;
+ }
+
+ if (bounds == null || existingBounds.width() != bounds.width()
+ || existingBounds.height() != bounds.height()) {
+ boundsChange |= BOUNDS_CHANGE_SIZE;
+ }
+
+ return boundsChange;
+ }
+
int diffRequestedOverrideBounds(Rect bounds) {
if (equivalentRequestedOverrideBounds(bounds)) {
return BOUNDS_CHANGE_NONE;
@@ -340,10 +405,6 @@
return boundsChange;
}
- boolean hasOverrideConfiguration() {
- return mHasOverrideConfiguration;
- }
-
public WindowConfiguration getWindowConfiguration() {
return mFullConfiguration.windowConfiguration;
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 546c5d4..6ffb482 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -25,6 +25,7 @@
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA;
import static com.android.server.wm.DisplayAreaProto.NAME;
import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -194,6 +195,7 @@
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(NAME, mName);
+ proto.write(IS_TASK_DISPLAY_AREA, isTaskDisplayArea());
proto.end(token);
}
@@ -349,6 +351,15 @@
return info;
}
+ @Override
+ public boolean providesMaxBounds() {
+ return true;
+ }
+
+ protected boolean isTaskDisplayArea() {
+ return false;
+ }
+
/**
* DisplayArea that contains WindowTokens, and orders them according to their type.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0b1f4d9e..fc17053 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1930,6 +1930,7 @@
final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config);
calculateBounds(displayInfo, mTmpBounds);
config.windowConfiguration.setBounds(mTmpBounds);
+ config.windowConfiguration.setMaxBounds(mTmpBounds);
config.windowConfiguration.setWindowingMode(getWindowingMode());
config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
@@ -2544,10 +2545,6 @@
return mDisplayAreaPolicy.getDefaultTaskDisplayArea();
}
- void positionDisplayAt(int position, boolean includingParents) {
- getParent().positionChildAt(position, this, includingParents);
- }
-
/**
* Returns true if the input point is within an app window.
*/
@@ -5393,6 +5390,11 @@
});
}
+ @Override
+ public boolean providesMaxBounds() {
+ return true;
+ }
+
/** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
@@ -5403,6 +5405,9 @@
*/
private ActivityRecord mAnimatingRecents;
+ /** Whether {@link #mAnimatingRecents} is going to be the top activity. */
+ private boolean mRecentsWillBeTop;
+
/**
* If the recents activity has a fixed orientation which is different from the current top
* activity, it will be rotated before being shown so we avoid a screen rotation animation
@@ -5428,10 +5433,12 @@
* If {@link #mAnimatingRecents} still has fixed rotation, it should be moved to top so we
* don't clear {@link #mFixedRotationLaunchingApp} that will be handled by transition.
*/
- void onFinishRecentsAnimation(boolean moveRecentsToBack) {
+ void onFinishRecentsAnimation() {
final ActivityRecord animatingRecents = mAnimatingRecents;
+ final boolean recentsWillBeTop = mRecentsWillBeTop;
mAnimatingRecents = null;
- if (!moveRecentsToBack) {
+ mRecentsWillBeTop = false;
+ if (recentsWillBeTop) {
// The recents activity will be the top, such as staying at recents list or
// returning to home (if home and recents are the same activity).
return;
@@ -5454,6 +5461,10 @@
}
}
+ void notifyRecentsWillBeTop() {
+ mRecentsWillBeTop = true;
+ }
+
/**
* Return {@code true} if there is an ongoing animation to the "Recents" activity and this
* activity as a fixed orientation so shouldn't be rotated.
@@ -5474,6 +5485,14 @@
if (r == null || r == mAnimatingRecents) {
return;
}
+ if (mAnimatingRecents != null && mRecentsWillBeTop) {
+ // The activity is not the recents and it should be moved to back later, so it is
+ // better to keep its current appearance for the next transition. Otherwise the
+ // display orientation may be updated too early and the layout procedures at the
+ // end of finishing recents animation is skipped. That causes flickering because
+ // the surface of closing app hasn't updated to invisible.
+ return;
+ }
if (mFixedRotationLaunchingApp == null) {
// In most cases this is a no-op if the activity doesn't have fixed rotation.
// Otherwise it could be from finishing recents animation while the display has
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 0e24fc8..4f6f75d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -356,6 +356,8 @@
private WindowState mFocusedWindow;
private WindowState mLastFocusedWindow;
+ private WindowState mSystemUiControllingWindow;
+
// The states of decor windows from the last layout. These are used to generate another display
// layout in different bounds but with the same states.
private boolean mLastNavVisible;
@@ -3436,6 +3438,7 @@
}
}
final WindowState win = winCandidate;
+ mSystemUiControllingWindow = win;
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
@@ -3740,8 +3743,12 @@
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
final boolean hideStatusBarSysui =
(vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
- final boolean hideNavBarSysui =
- (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+ final boolean hideNavBarSysui = (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+ // We shouldn't rely on the system UI visibilities anymore because the window can
+ // use the new API (e.g., WindowInsetsController.hide) to hide navigation bar.
+ // TODO(b/149813814): clean up the system UI flag usages in this function.
+ || !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR);
final boolean transientStatusBarAllowed = getStatusBar() != null
&& (notificationShadeHasFocus || (!mForceShowSystemBars
@@ -3755,15 +3762,16 @@
&& now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
final DisplayPolicy defaultDisplayPolicy =
mService.getDefaultDisplayContentLocked().getDisplayPolicy();
- if (pendingPanic && hideNavBarSysui && !isKeyguardShowing()
+ if (pendingPanic && hideNavBarSysui && win != mNotificationShade
+ && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
// TODO (b/111955725): Show keyguard presentation on all external displays
&& defaultDisplayPolicy.isKeyguardDrawComplete()) {
// The user performed the panic gesture recently, we're about to hide the bars,
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
- mStatusBarController.showTransient();
if (!isNavBarEmpty(vis)) {
- mNavigationBarController.showTransient();
+ mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+ new int[] {ITYPE_NAVIGATION_BAR}));
}
}
@@ -3908,6 +3916,9 @@
}
private boolean isImmersiveMode(WindowState win) {
+ if (win == null) {
+ return false;
+ }
final int behavior = win.mAttrs.insetsFlags.behavior;
return getNavigationBar() != null
&& canHideNavigationBar()
@@ -3942,11 +3953,7 @@
return;
}
mPendingPanicGestureUptime = SystemClock.uptimeMillis();
- if (!isNavBarEmpty(mLastSystemUiFlags)) {
- mNavigationBarController.showTransient();
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[] {ITYPE_NAVIGATION_BAR}));
- }
+ updateSystemUiVisibilityLw();
}
}
};
@@ -3955,7 +3962,7 @@
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
- SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
+ SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index f5bd4cd..6b3a5d6 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -702,6 +702,11 @@
"cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
+ "reorderMode=%d",
mPendingAnimations.size(), reorderMode);
+ if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) {
+ // Notify the state at the beginning because the removeAnimation may notify the
+ // transition is finished. This is a signal that there will be a next transition.
+ mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop();
+ }
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
@@ -742,8 +747,7 @@
mTargetActivityRecord.token);
}
}
- mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(
- reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION /* moveRecentsToBack */);
+ mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
// Notify that the animation has ended
if (mStatusBar != null) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 06dec7c..526ec08 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2751,7 +2751,7 @@
if (r.app != app) return;
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- r.app = null;
+ r.detachFromProcess();
r.getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.destroyIfPossible("handleAppCrashed");
@@ -3104,22 +3104,6 @@
return null;
}
- boolean handleAppDied(WindowProcessController app) {
- if (app.isRemoved()) {
- // The package of the died process should be force-stopped, so make its activities as
- // finishing to prevent the process from being started again if the next top (or being
- // visible) activity also resides in the same process.
- app.makeFinishingForProcessRemoved();
- }
- return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
- result |= stack.handleAppDied(app);
- }
- return result;
- }, false /* initValue */);
- }
-
void closeSystemDialogActivities(String reason) {
forAllActivities((r) -> {
if ((r.info.flags & ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index da1e426..f362005 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -86,8 +86,6 @@
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
@@ -115,8 +113,6 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
-import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
-import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -129,7 +125,6 @@
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
-import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
import static com.android.server.wm.TaskProto.BOUNDS;
import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DISPLAY_ID;
@@ -600,16 +595,6 @@
SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
Task mMainWindowSizeChangeTask;
- // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
- // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
- // would otherwise apply while resizing, while resizing in the bounds animating mode.
- private boolean mBoundsAnimating = false;
- // Set when an animation has been requested but has not yet started from the UI thread. This is
- // cleared when the animation actually starts.
- private boolean mBoundsAnimatingRequested = false;
- private Rect mBoundsAnimationTarget = new Rect();
- private Rect mBoundsAnimationSourceHintBounds = new Rect();
-
Rect mPreAnimationBounds = new Rect();
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
@@ -757,111 +742,6 @@
}
}
- // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
- private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
- new RemoveHistoryRecordsForApp();
- private class RemoveHistoryRecordsForApp {
- private boolean mHasVisibleActivities;
- private boolean mIsProcessRemoved;
- private WindowProcessController mApp;
- private ArrayList<ActivityRecord> mToRemove = new ArrayList<>();
-
- boolean process(WindowProcessController app) {
- mToRemove.clear();
- mHasVisibleActivities = false;
- mApp = app;
- mIsProcessRemoved = app.isRemoved();
-
- final PooledConsumer c = PooledLambda.obtainConsumer(
- RemoveHistoryRecordsForApp::addActivityToRemove, this,
- PooledLambda.__(ActivityRecord.class));
- forAllActivities(c);
- c.recycle();
-
- while (!mToRemove.isEmpty()) {
- processActivity(mToRemove.remove(0));
- }
-
- mApp = null;
- return mHasVisibleActivities;
- }
-
- private void addActivityToRemove(ActivityRecord r) {
- if (r.app == mApp) {
- mToRemove.add(r);
- }
- }
-
- private void processActivity(ActivityRecord r) {
- if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app);
-
- if (r.app != mApp) {
- return;
- }
- if (r.isVisible() || r.mVisibleRequested) {
- // While an activity launches a new activity, it's possible that the old
- // activity is already requested to be hidden (mVisibleRequested=false), but
- // this visibility is not yet committed, so isVisible()=true.
- mHasVisibleActivities = true;
- }
- final boolean remove;
- if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
- || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
- && r.launchCount < 3 && !r.finishing) {
- // If the process crashed during a resize, always try to relaunch it, unless
- // it has failed more than twice. Skip activities that's already finishing
- // cleanly by itself.
- remove = false;
- } else if ((!r.hasSavedState() && !r.stateNotNeeded
- && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
- // Don't currently have state for the activity, or
- // it is finishing -- always remove it.
- remove = true;
- } else if (!r.mVisibleRequested && r.launchCount > 2
- && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
- // We have launched this activity too many times since it was
- // able to run, so give up and remove it.
- // (Note if the activity is visible, we don't remove the record.
- // We leave the dead window on the screen but the process will
- // not be restarted unless user explicitly tap on it.)
- remove = true;
- } else {
- // The process may be gone, but the activity lives on!
- remove = false;
- }
- if (remove) {
- if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
- "Removing activity " + r + " from stack "
- + ": hasSavedState=" + r.hasSavedState()
- + " stateNotNeeded=" + r.stateNotNeeded
- + " finishing=" + r.finishing
- + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
- if (!r.finishing || mIsProcessRemoved) {
- Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
- EventLogTags.writeWmFinishActivity(r.mUserId,
- System.identityHashCode(r), r.getTask().mTaskId,
- r.shortComponentName, "proc died without state saved");
- }
- } else {
- // We have the current state for this activity, so
- // it can be restarted later when needed.
- if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
- if (DEBUG_APP) Slog.v(TAG_APP,
- "Clearing app during removeHistory for activity " + r);
- r.app = null;
- // Set nowVisible to previous visible state. If the app was visible while
- // it died, we leave the dead window on screen so it's basically visible.
- // This is needed when user later tap on the dead window, we need to stop
- // other apps when user transfers focus to the restarted activity.
- r.nowVisible = r.mVisibleRequested;
- }
- r.cleanUp(true /* cleanServices */, true /* setState */);
- if (remove) {
- r.removeFromHistory("appDied");
- }
- }
- }
-
private final FindRootHelper mFindRootHelper = new FindRootHelper();
private class FindRootHelper {
private ActivityRecord mRoot;
@@ -3741,17 +3621,6 @@
}
@Override
- public SurfaceControl getAnimationLeashParent() {
- if (WindowManagerService.sHierarchicalAnimations) {
- return super.getAnimationLeashParent();
- }
- // Currently, only the recents animation will create animation leashes for tasks. In this
- // case, reparent the task to the home animation layer while it is being animated to allow
- // the home activity to reorder the app windows relative to its own.
- return getAppAnimationLayer(ANIMATION_LAYER_HOME);
- }
-
- @Override
void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
if (isOrganized()) return;
super.resetSurfacePositionForAnimationLeash(t);
@@ -7132,14 +7001,6 @@
forAllTasks(c, true /* traverseTopToBottom */);
c.recycle();
- if (mBoundsAnimating) {
- // Force to update task surface bounds and relayout windows, since configBounds
- // remains unchanged during bounds animation.
- updateSurfaceBounds();
- getDisplay().setLayoutNeeded();
- mWmService.requestTraversal();
- }
-
if (!deferResume) {
ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
}
@@ -7197,9 +7058,8 @@
/**
* Reset local parameters because an app's activity died.
* @param app The app of the activity that died.
- * @return result from removeHistoryRecordsForAppLocked.
*/
- boolean handleAppDied(WindowProcessController app) {
+ void handleAppDied(WindowProcessController app) {
if (mPausingActivity != null && mPausingActivity.app == app) {
if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
"App died while pausing: " + mPausingActivity);
@@ -7209,9 +7069,6 @@
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
-
- mStackSupervisor.removeHistoryRecords(app);
- return mRemoveHistoryRecordsForApp.process(app);
}
boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
@@ -7541,20 +7398,6 @@
}
/**
- * @return the final bounds for the bounds animation.
- */
- void getFinalAnimationBounds(Rect outBounds) {
- outBounds.set(mBoundsAnimationTarget);
- }
-
- /**
- * @return the final source bounds for the bounds animation.
- */
- void getFinalAnimationSourceHintBounds(Rect outBounds) {
- outBounds.set(mBoundsAnimationSourceHintBounds);
- }
-
- /**
* Put a Task in this stack. Used for adding only.
* When task is added to top of the stack, the entire branch of the hierarchy (including stack
* and display) will be brought to top.
@@ -7709,10 +7552,6 @@
getDisplayContent().getPinnedStackController().setActions(actions);
}
- public boolean isForceScaled() {
- return mBoundsAnimating;
- }
-
/** Returns true if a removal action is still being deferred. */
boolean handleCompleteDeferredRemoval() {
if (isAnimating(TRANSITION | CHILDREN)) {
@@ -7799,8 +7638,6 @@
mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
}
- proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
-
if (mSurfaceControl != null) {
proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 246753a..a847744 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1294,7 +1294,13 @@
}
void onSplitScreenModeDismissed() {
- onSplitScreenModeDismissed(null /* toTop */);
+ // The focused task could be a non-resizeable fullscreen root task that is on top of the
+ // other split-screen tasks, therefore had to dismiss split-screen, make sure the current
+ // focused root task can still be on top after dismissal
+ final Task rootTask = getFocusedStack();
+ final Task toTop =
+ rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null;
+ onSplitScreenModeDismissed(toTop);
}
void onSplitScreenModeDismissed(Task toTop) {
@@ -1838,6 +1844,10 @@
return lastReparentedStack;
}
+ @Override
+ protected boolean isTaskDisplayArea() {
+ return true;
+ }
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 9d0bac9..6377a21 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -68,7 +68,6 @@
Object mLastWindowFreezeSource;
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
-
private boolean mInitialized = false;
// When set to true the animator will go over all windows after an animation frame is posted and
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index f37fe3a..e24d185 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -51,7 +51,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowManagerService.sHierarchicalAnimations;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import android.annotation.CallSuper;
@@ -858,6 +857,14 @@
}
/**
+ * @return {@code true} when an application can override an app transition animation on this
+ * container.
+ */
+ boolean canCustomizeAppTransition() {
+ return !WindowManagerService.sDisableCustomTaskAnimationProperty;
+ }
+
+ /**
* @return {@code true} when this container or its related containers are running an
* animation, {@code false} otherwise.
*
@@ -2366,10 +2373,6 @@
final Rect screenBounds = getAnimationBounds(appStackClipMode);
mTmpRect.set(screenBounds);
getAnimationPosition(mTmpPoint);
- if (!sHierarchicalAnimations) {
- // Non-hierarchical animation uses position in global coordinates.
- mTmpPoint.set(mTmpRect.left, mTmpRect.top);
- }
mTmpRect.offsetTo(0, 0);
final RemoteAnimationController controller =
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2dd25c9..ede92f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -396,24 +396,23 @@
private static final boolean ALWAYS_KEEP_CURRENT = true;
/**
- * If set, new app transition framework which supports setting animation on any element
- * in a surface is used.
- * <p>
- * Only set this to non-zero once the new app transition framework is productionalized.
- * </p>
+ * Restrict ability of activities overriding transition animation in a way such that
+ * an activity can do it only when the transition happens within a same task.
+ *
+ * @see android.app.Activity#overridePendingTransition(int, int)
*/
- private static final String HIERARCHICAL_ANIMATIONS_PROPERTY =
- "persist.wm.hierarchical_animations";
+ private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
+ "persist.wm.disable_custom_task_animation";
+
+ /**
+ * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
+ */
+ static boolean sDisableCustomTaskAnimationProperty =
+ SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, false);
private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
"ro.sf.disable_triple_buffer";
- /**
- * @see #HIERARCHICAL_ANIMATIONS_PROPERTY
- */
- static boolean sHierarchicalAnimations =
- SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, true);
-
static boolean sEnableTripleBuffering = !SystemProperties.getBoolean(
DISABLE_TRIPLE_BUFFERING_PROPERTY, false);
@@ -2931,8 +2930,8 @@
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null && mRoot.getTopChild() != displayContent) {
- displayContent.positionDisplayAt(WindowContainer.POSITION_TOP,
- true /* includingParents */);
+ displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
+ displayContent, true /* includingParents */);
}
}
syncInputTransactions();
@@ -8017,7 +8016,7 @@
final DisplayContent displayContent = touchedWindow.getDisplayContent();
if (!displayContent.isOnTop()) {
- displayContent.positionDisplayAt(WindowContainer.POSITION_TOP,
+ displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
true /* includingParents */);
}
handleTaskFocusChange(touchedWindow.getTask());
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 6ba8769..df59c56 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -177,8 +177,10 @@
// Whether this process has ever started a service with the BIND_INPUT_METHOD permission.
private volatile boolean mHasImeService;
- // all activities running in the process
+ /** All activities running in the process (exclude destroying). */
private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
+ /** The activities will be removed but still belong to this process. */
+ private ArrayList<ActivityRecord> mInactiveActivities;
// any tasks this process had run root activities in
private final ArrayList<Task> mRecentTasks = new ArrayList<>();
// The most recent top-most activity that was resumed in the process for pre-Q app.
@@ -635,21 +637,39 @@
return;
}
mActivities.add(r);
+ if (mInactiveActivities != null) {
+ mInactiveActivities.remove(r);
+ }
updateActivityConfigurationListener();
}
- void removeActivity(ActivityRecord r) {
+ /**
+ * Indicates that the given activity is no longer active in this process.
+ *
+ * @param r The running activity to be removed.
+ * @param keepAssociation {@code true} if the activity still belongs to this process but will
+ * be removed soon, e.g. destroying. From the perspective of process
+ * priority, the process is not important if it only contains activities
+ * that are being destroyed. But the association is still needed to
+ * ensure all activities are reachable from this process.
+ */
+ void removeActivity(ActivityRecord r, boolean keepAssociation) {
+ if (keepAssociation) {
+ if (mInactiveActivities == null) {
+ mInactiveActivities = new ArrayList<>();
+ mInactiveActivities.add(r);
+ } else if (!mInactiveActivities.contains(r)) {
+ mInactiveActivities.add(r);
+ }
+ } else if (mInactiveActivities != null) {
+ mInactiveActivities.remove(r);
+ }
mActivities.remove(r);
updateActivityConfigurationListener();
}
- void makeFinishingForProcessRemoved() {
- for (int i = mActivities.size() - 1; i >= 0; --i) {
- mActivities.get(i).makeFinishingLocked();
- }
- }
-
void clearActivities() {
+ mInactiveActivities = null;
mActivities.clear();
updateActivityConfigurationListener();
}
@@ -1142,6 +1162,47 @@
mAtm.mH.sendMessage(m);
}
+ /**
+ * Clean up the activities belonging to this process.
+ *
+ * @return {@code true} if the process has any visible activity.
+ */
+ boolean handleAppDied() {
+ mAtm.mStackSupervisor.removeHistoryRecords(this);
+
+ final boolean isRemoved = isRemoved();
+ boolean hasVisibleActivities = false;
+ if (mInactiveActivities != null && !mInactiveActivities.isEmpty()) {
+ // Make sure that all activities in this process are handled.
+ mActivities.addAll(mInactiveActivities);
+ }
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.mVisibleRequested || r.isVisible()) {
+ // While an activity launches a new activity, it's possible that the old activity
+ // is already requested to be hidden (mVisibleRequested=false), but this visibility
+ // is not yet committed, so isVisible()=true.
+ hasVisibleActivities = true;
+ }
+ if (isRemoved) {
+ // The package of the died process should be force-stopped, so make its activities
+ // as finishing to prevent the process from being started again if the next top (or
+ // being visible) activity also resides in the same process.
+ r.makeFinishingLocked();
+ }
+
+ final Task rootTask = r.getRootTask();
+ if (rootTask != null) {
+ rootTask.handleAppDied(this);
+ }
+ r.handleAppDied();
+ }
+ clearRecentTasks();
+ clearActivities();
+
+ return hasVisibleActivities;
+ }
+
void registerDisplayConfigurationListener(DisplayContent displayContent) {
if (displayContent == null) {
return;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 77fee85..d0101ad 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -208,16 +208,6 @@
int mAttrType;
- boolean mForceScaleUntilResize;
-
- // WindowState.mHScale and WindowState.mVScale contain the
- // scale according to client specified layout parameters (e.g.
- // one layout size, with another surface size, creates such scaling).
- // Here we track an additional scaling factor used to follow stack
- // scaling (as in the case of the Pinned stack animation).
- float mExtraHScale = (float) 1.0;
- float mExtraVScale = (float) 1.0;
-
// An offset in pixel of the surface contents from the window position. Used for Wallpaper
// to provide the effect of scrolling within a large surface. We just use these values as
// a cache.
@@ -247,11 +237,6 @@
private final SurfaceControl.Transaction mPostDrawTransaction =
new SurfaceControl.Transaction();
- // Set to true after the first frame of the Pinned stack animation
- // and reset after the last to ensure we only reset mForceScaleUntilResize
- // once per animation.
- boolean mPipAnimationStarted = false;
-
private final Point mTmpPos = new Point();
WindowStateAnimator(final WindowState win) {
@@ -870,11 +855,6 @@
calculateSurfaceBounds(w, attrs, mTmpSize);
- mExtraHScale = (float) 1.0;
- mExtraVScale = (float) 1.0;
-
- boolean wasForceScaled = mForceScaleUntilResize;
-
// Once relayout has been called at least once, we need to make sure
// we only resize the client surface during calls to relayout. For
// clients which use indeterminate measure specs (MATCH_PARENT),
@@ -889,7 +869,6 @@
} else {
mSurfaceResized = false;
}
- mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
// If we are undergoing seamless rotation, the surface has already
// been set up to persist at it's old location. We need to freeze
// updates until a resize occurs.
@@ -913,184 +892,54 @@
final Rect insets = attrs.surfaceInsets;
- if (isForceScaled()) {
- int hInsets = insets.left + insets.right;
- int vInsets = insets.top + insets.bottom;
- float surfaceContentWidth = surfaceWidth - hInsets;
- float surfaceContentHeight = surfaceHeight - vInsets;
- if (!mForceScaleUntilResize) {
- mSurfaceController.forceScaleableInTransaction(true);
- }
-
- int posX = 0;
- int posY = 0;
- task.getRootTask().getDimBounds(mTmpStackBounds);
-
- boolean allowStretching = false;
- task.getRootTask().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
- // If we don't have source bounds, we can attempt to use the content insets
- // if we have content insets.
- if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
- || mWin.mLastRelayoutContentInsets.height() > 0)) {
- mTmpSourceBounds.set(task.getRootTask().mPreAnimationBounds);
- mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
- allowStretching = true;
- }
-
- // Make sure that what we're animating to and from is actually the right size in case
- // the window cannot take up the full screen.
- mTmpStackBounds.intersectUnchecked(w.getParentFrame());
- mTmpSourceBounds.intersectUnchecked(w.getParentFrame());
- mTmpAnimatingBounds.intersectUnchecked(w.getParentFrame());
-
- if (!mTmpSourceBounds.isEmpty()) {
- // Get the final target stack bounds, if we are not animating, this is just the
- // current stack bounds
- task.getRootTask().getFinalAnimationBounds(mTmpAnimatingBounds);
-
- // Calculate the current progress and interpolate the difference between the target
- // and source bounds
- float finalWidth = mTmpAnimatingBounds.width();
- float initialWidth = mTmpSourceBounds.width();
- float tw = (surfaceContentWidth - mTmpStackBounds.width())
- / (surfaceContentWidth - mTmpAnimatingBounds.width());
- float th = tw;
- mExtraHScale = (initialWidth + tw * (finalWidth - initialWidth)) / initialWidth;
- if (allowStretching) {
- float finalHeight = mTmpAnimatingBounds.height();
- float initialHeight = mTmpSourceBounds.height();
- th = (surfaceContentHeight - mTmpStackBounds.height())
- / (surfaceContentHeight - mTmpAnimatingBounds.height());
- mExtraVScale = (initialHeight + tw * (finalHeight - initialHeight))
- / initialHeight;
+ if (!w.mSeamlesslyRotated) {
+ // Used to offset the WSA when stack position changes before a resize.
+ int xOffset = mXOffset;
+ int yOffset = mYOffset;
+ if (mOffsetPositionForStackResize) {
+ if (relayout) {
+ // Once a relayout is called, reset the offset back to 0 and defer
+ // setting it until a new frame with the updated size. This ensures that
+ // the WS position is reset (so the stack position is shown) at the same
+ // time that the buffer size changes.
+ setOffsetPositionForStackResize(false);
+ mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
+ mWin.getFrameNumber());
} else {
- mExtraVScale = mExtraHScale;
- }
-
- // Adjust the position to account for the inset bounds
- posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left);
- posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top);
-
- // In pinned mode the clip rectangle applied to us by our stack has been
- // expanded outwards to allow for shadows. However in case of source bounds set
- // we need to crop to within the surface. The code above has scaled and positioned
- // the surface to fit the unexpanded stack bounds, but now we need to reapply
- // the cropping that the stack would have applied if it weren't expanded. This
- // can be different in each direction based on the source bounds.
- clipRect = mTmpClipRect;
- clipRect.set((int)((insets.left + mTmpSourceBounds.left) * tw),
- (int)((insets.top + mTmpSourceBounds.top) * th),
- insets.left + (int)(surfaceWidth
- - (tw* (surfaceWidth - mTmpSourceBounds.right))),
- insets.top + (int)(surfaceHeight
- - (th * (surfaceHeight - mTmpSourceBounds.bottom))));
- } else {
- // We want to calculate the scaling based on the content area, not based on
- // the entire surface, so that we scale in sync with windows that don't have insets.
- mExtraHScale = mTmpStackBounds.width() / surfaceContentWidth;
- mExtraVScale = mTmpStackBounds.height() / surfaceContentHeight;
-
- // Since we are scaled to fit in our previously desired crop, we can now
- // expose the whole window in buffer space, and not risk extending
- // past where the system would have cropped us
- clipRect = null;
- }
-
- // In the case of ForceScaleToStack we scale entire tasks together,
- // and so we need to scale our offsets relative to the task bounds
- // or parent and child windows would fall out of alignment.
- posX -= (int) (attrs.x * (1 - mExtraHScale));
- posY -= (int) (attrs.y * (1 - mExtraVScale));
-
- // Imagine we are scaling down. As we scale the buffer down, we decrease the
- // distance between the surface top left, and the start of the surface contents
- // (previously it was surfaceInsets.left pixels in screen space but now it
- // will be surfaceInsets.left*mExtraHScale). This means in order to keep the
- // non inset content at the same position, we have to shift the whole window
- // forward. Likewise for scaling up, we've increased this distance, and we need
- // to shift by a negative number to compensate.
- posX += insets.left * (1 - mExtraHScale);
- posY += insets.top * (1 - mExtraVScale);
-
- mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
- (float) Math.floor(posY), recoveringMemory);
-
- // Various surfaces in the scaled stack may resize at different times.
- // We need to ensure for each surface, that we disable transformation matrix
- // scaling in the same transaction which we resize the surface in.
- // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
- // then take over the scaling until the new buffer arrives, and things
- // will be seamless.
- if (mPipAnimationStarted == false) {
- mForceScaleUntilResize = true;
- mPipAnimationStarted = true;
- }
- } else {
- mPipAnimationStarted = false;
-
- if (!w.mSeamlesslyRotated) {
- // Used to offset the WSA when stack position changes before a resize.
- int xOffset = mXOffset;
- int yOffset = mYOffset;
- if (mOffsetPositionForStackResize) {
- if (relayout) {
- // Once a relayout is called, reset the offset back to 0 and defer
- // setting it until a new frame with the updated size. This ensures that
- // the WS position is reset (so the stack position is shown) at the same
- // time that the buffer size changes.
- setOffsetPositionForStackResize(false);
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
- } else {
- final Task stack = mWin.getRootTask();
- mTmpPos.x = 0;
- mTmpPos.y = 0;
- if (stack != null) {
- stack.getRelativePosition(mTmpPos);
- }
-
- xOffset = -mTmpPos.x;
- yOffset = -mTmpPos.y;
-
- // Crop also needs to be extended so the bottom isn't cut off when the WSA
- // position is moved.
- if (clipRect != null) {
- clipRect.right += mTmpPos.x;
- clipRect.bottom += mTmpPos.y;
- }
+ final Task stack = mWin.getRootTask();
+ mTmpPos.x = 0;
+ mTmpPos.y = 0;
+ if (stack != null) {
+ stack.getRelativePosition(mTmpPos);
+ }
+ xOffset = -mTmpPos.x;
+ yOffset = -mTmpPos.y;
+ // Crop also needs to be extended so the bottom isn't cut off when the WSA
+ // position is moved.
+ if (clipRect != null) {
+ clipRect.right += mTmpPos.x;
+ clipRect.bottom += mTmpPos.y;
}
}
- if (!mIsWallpaper) {
- mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
- } else {
- setWallpaperPositionAndScale(
- xOffset, yOffset, mWallpaperScale, recoveringMemory);
- }
+ }
+ if (!mIsWallpaper) {
+ mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(
+ xOffset, yOffset, mWallpaperScale, recoveringMemory);
}
}
- // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
- // to prevent further updates until buffer latch.
- // We also need to freeze the Surface geometry until a buffer
- // comes in at the new size (normally position and crop are unfrozen).
- // deferTransactionUntil accomplishes this for us.
- if (wasForceScaled && !mForceScaleUntilResize) {
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
- mSurfaceController.forceScaleableInTransaction(false);
- }
-
-
if (!w.mSeamlesslyRotated) {
// Wallpaper is already updated above when calling setWallpaperPositionAndScale so
// we only need to consider the non-wallpaper case here.
if (!mIsWallpaper) {
applyCrop(clipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(
- mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ mDsDx * w.mHScale,
+ mDtDx * w.mVScale,
+ mDtDy * w.mHScale,
+ mDsDy * w.mVScale, recoveringMemory);
}
}
@@ -1177,10 +1026,10 @@
} else {
prepared =
mSurfaceController.prepareToShowInTransaction(mShownAlpha,
- mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale,
+ mDsDx * w.mHScale,
+ mDtDx * w.mVScale,
+ mDtDy * w.mHScale,
+ mDsDy * w.mVScale,
recoveringMemory);
}
@@ -1287,10 +1136,10 @@
mSurfaceController.setPositionInTransaction(mWin.mTmpMatrixArray[MTRANS_X],
mWin.mTmpMatrixArray[MTRANS_Y], recoveringMemory);
mSurfaceController.setMatrixInTransaction(
- mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale * mExtraHScale,
- mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale * mExtraVScale,
- mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale * mExtraHScale,
- mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale * mExtraVScale,
+ mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale,
+ mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale,
+ mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale,
+ mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale,
recoveringMemory);
applyCrop(null, recoveringMemory);
}
@@ -1570,18 +1419,6 @@
}
}
- /** The force-scaled state for a given window can persist past
- * the state for it's stack as the windows complete resizing
- * independently of one another.
- */
- boolean isForceScaled() {
- final Task task = mWin.getTask();
- if (task != null && task.getRootTask().isForceScaled()) {
- return true;
- }
- return mForceScaleUntilResize;
- }
-
void detachChildren() {
// Do not detach children of starting windows, as their lifecycle is well under control and
diff --git a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
index 503f0cf..3dfce3a 100644
--- a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
+++ b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
@@ -235,7 +235,7 @@
return 0;
}
- // Sanity check - remove
+ // Soundness check - remove
if (gContext.device->notify != hal_notify_callback) {
ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 10523a2..7843663 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -239,9 +239,9 @@
void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
uint32_t policyFlags) override;
void notifyConfigurationChanged(nsecs_t when) override;
- std::chrono::nanoseconds notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token,
- const std::string& reason) override;
+ std::chrono::nanoseconds notifyAnr(
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) override;
void notifyInputChannelBroken(const sp<IBinder>& token) override;
void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
@@ -682,8 +682,8 @@
checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
}
-static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
- const sp<InputApplicationHandle>& inputApplicationHandle) {
+static jobject getInputApplicationHandleObjLocalRef(
+ JNIEnv* env, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
if (inputApplicationHandle == nullptr) {
return nullptr;
}
@@ -694,8 +694,8 @@
}
std::chrono::nanoseconds NativeInputManager::notifyAnr(
- const sp<InputApplicationHandle>& inputApplicationHandle, const sp<IBinder>& token,
- const std::string& reason) {
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -780,8 +780,12 @@
void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
jobject applicationHandleObj) {
- sp<InputApplicationHandle> applicationHandle =
+ if (!applicationHandleObj) {
+ return;
+ }
+ std::shared_ptr<InputApplicationHandle> applicationHandle =
android_view_InputApplicationHandle_getHandle(env, applicationHandleObj);
+ applicationHandle->updateInfo();
mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle);
}
diff --git a/services/core/jni/stats/PowerStatsPuller.cpp b/services/core/jni/stats/PowerStatsPuller.cpp
index d8f6faa..7f788c2 100644
--- a/services/core/jni/stats/PowerStatsPuller.cpp
+++ b/services/core/jni/stats/PowerStatsPuller.cpp
@@ -135,16 +135,11 @@
}
const RailInfo& rail = gRailInfo[energyData.index];
- AStatsEvent* event =
- AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(
- event,
- android::util::ON_DEVICE_POWER_MEASUREMENT);
- AStatsEvent_writeString(event, rail.subsysName.c_str());
- AStatsEvent_writeString(event, rail.railName.c_str());
- AStatsEvent_writeInt64(event, energyData.timestamp);
- AStatsEvent_writeInt64(event, energyData.energy);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(
+ data,
+ android::util::ON_DEVICE_POWER_MEASUREMENT,
+ rail.subsysName.c_str(), rail.railName.c_str(),
+ energyData.timestamp, energyData.energy);
ALOGV("power.stat: %s.%s: %llu, %llu",
rail.subsysName.c_str(), rail.railName.c_str(),
diff --git a/services/core/jni/stats/SubsystemSleepStatePuller.cpp b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
index 45afb5e..1ba98ef 100644
--- a/services/core/jni/stats/SubsystemSleepStatePuller.cpp
+++ b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
@@ -194,17 +194,13 @@
}
for (auto result : results) {
for (auto stateResidency : result.stateResidencyData) {
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event,
- gEntityNames.at(result.powerEntityId).c_str());
- AStatsEvent_writeString(event,
- gStateNames.at(result.powerEntityId)
- .at(stateResidency.powerEntityStateId)
- .c_str());
- AStatsEvent_writeInt64(event, stateResidency.totalStateEntryCount);
- AStatsEvent_writeInt64(event, stateResidency.totalTimeInStateMs);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
+ gEntityNames.at(result.powerEntityId).c_str(),
+ gStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId)
+ .c_str(),
+ stateResidency.totalStateEntryCount,
+ stateResidency.totalTimeInStateMs);
}
}
success = true;
@@ -259,26 +255,21 @@
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeString(event, "");
- AStatsEvent_writeInt64(event, state.totalTransitions);
- AStatsEvent_writeInt64(event, state.residencyInMsecSinceBoot);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
+ state.name.c_str(), "",
+ state.totalTransitions,
+ state.residencyInMsecSinceBoot);
ALOGV("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions,
state.supportedOnlyInSuspend ? 1 : 0);
for (const auto& voter : state.voters) {
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeString(event, voter.name.c_str());
- AStatsEvent_writeInt64(event, voter.totalNumberOfTimesVotedSinceBoot);
- AStatsEvent_writeInt64(event, voter.totalTimeInMsecVotedForSinceBoot);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data,
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ state.name.c_str(), voter.name.c_str(),
+ voter.totalNumberOfTimesVotedSinceBoot,
+ voter.totalTimeInMsecVotedForSinceBoot);
ALOGV("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
voter.name.c_str(),
@@ -305,14 +296,13 @@
for (size_t j = 0; j < subsystem.states.size(); j++) {
const PowerStateSubsystemSleepState& state =
subsystem.states[j];
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event,
- android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, subsystem.name.c_str());
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeInt64(event, state.totalTransitions);
- AStatsEvent_writeInt64(event, state.residencyInMsecSinceBoot);
- AStatsEvent_build(event);
+ android::util::
+ addAStatsEvent(data,
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ subsystem.name.c_str(),
+ state.name.c_str(),
+ state.totalTransitions,
+ state.residencyInMsecSinceBoot);
ALOGV("subsystemstate: %s, %s, %lld, %lld, %lld",
subsystem.name.c_str(), state.name.c_str(),
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7ec819f..9a2bef8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -290,6 +290,7 @@
import com.android.server.PersistentDataBlockManagerInternal;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -775,18 +776,18 @@
}
@Override
- public void onStartUser(int userHandle) {
- mService.handleStartUser(userHandle);
+ public void onUserStarting(@NonNull TargetUser user) {
+ mService.handleStartUser(user.getUserIdentifier());
}
@Override
- public void onUnlockUser(int userHandle) {
- mService.handleUnlockUser(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mService.handleUnlockUser(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mService.handleStopUser(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mService.handleStopUser(user.getUserIdentifier());
}
}
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 51478b3..2cfdf3f 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -16,6 +16,7 @@
package com.android.server.midi;
+import android.annotation.NonNull;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
@@ -47,8 +48,8 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.XmlUtils;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
@@ -75,8 +76,8 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- if (userHandle == UserHandle.USER_SYSTEM) {
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ if (user.getUserIdentifier() == UserHandle.USER_SYSTEM) {
mMidiService.onUnlockUser();
}
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index d064f7e..1cdcbd8 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -72,6 +72,7 @@
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,13 +102,13 @@
}
@Override
- public void onUnlockUser(int userHandle) {
- mPrintManagerImpl.handleUserUnlocked(userHandle);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mPrintManagerImpl.handleUserUnlocked(user.getUserIdentifier());
}
@Override
- public void onStopUser(int userHandle) {
- mPrintManagerImpl.handleUserStopped(userHandle);
+ public void onUserStopping(@NonNull TargetUser user) {
+ mPrintManagerImpl.handleUserStopped(user.getUserIdentifier());
}
class PrintManagerImpl extends IPrintManager.Stub {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index 4a73efe..cd9b6ac 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -38,7 +38,6 @@
import android.annotation.UserIdInt;
import android.app.Application;
-import android.app.backup.BackupManager;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
@@ -46,6 +45,7 @@
import android.app.backup.ISelectBackupTransportCallback;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserInfo;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -54,6 +54,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
+import com.android.server.SystemService.TargetUser;
import com.android.server.backup.testing.TransportData;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
@@ -1601,7 +1602,7 @@
BackupManagerService.Lifecycle lifecycle =
new BackupManagerService.Lifecycle(mContext, backupManagerService);
- lifecycle.onUnlockUser(UserHandle.USER_SYSTEM);
+ lifecycle.onUserUnlocking(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
verify(backupManagerService).onUnlockUser(UserHandle.USER_SYSTEM);
}
@@ -1613,7 +1614,7 @@
BackupManagerService.Lifecycle lifecycle =
new BackupManagerService.Lifecycle(mContext, backupManagerService);
- lifecycle.onStopUser(UserHandle.USER_SYSTEM);
+ lifecycle.onUserStopping(new TargetUser(new UserInfo(UserHandle.USER_SYSTEM, null, 0)));
verify(backupManagerService).onStopUser(UserHandle.USER_SYSTEM);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 8ccaedd..2f5e883 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -247,7 +247,7 @@
.thenAnswer(inv -> getPowerSaveState());
when(mMockAppOpsManager.getPackagesForOps(
any(int[].class)
- )).thenAnswer(mGetPackagesForOps);
+ )).thenAnswer(mGetPackagesForOps);
mMockContentResolver = new MockContentResolver();
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
@@ -447,7 +447,7 @@
areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- // Clear the app ops and update the whitelist.
+ // Clear the app ops and update the exemption list.
setAppOps(UID_1, PACKAGE_1, false);
setAppOps(UID_10_2, PACKAGE_2, false);
@@ -462,7 +462,8 @@
areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_1}, new int[] {},
+ new int[] {UID_2});
areRestricted(instance, UID_1, PACKAGE_1, NONE);
areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
@@ -487,24 +488,25 @@
areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- assertTrue(instance.isUidPowerSaveWhitelisted(UID_1));
- assertTrue(instance.isUidPowerSaveWhitelisted(UID_10_1));
- assertFalse(instance.isUidPowerSaveWhitelisted(UID_2));
- assertFalse(instance.isUidPowerSaveWhitelisted(UID_10_2));
+ assertTrue(instance.isUidPowerSaveExempt(UID_1));
+ assertTrue(instance.isUidPowerSaveExempt(UID_10_1));
+ assertFalse(instance.isUidPowerSaveExempt(UID_2));
+ assertFalse(instance.isUidPowerSaveExempt(UID_10_2));
- assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_1));
- assertFalse(instance.isUidTempPowerSaveWhitelisted(UID_10_1));
- assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_2));
- assertTrue(instance.isUidTempPowerSaveWhitelisted(UID_10_2));
+ assertFalse(instance.isUidTempPowerSaveExempt(UID_1));
+ assertFalse(instance.isUidTempPowerSaveExempt(UID_10_1));
+ assertTrue(instance.isUidTempPowerSaveExempt(UID_2));
+ assertTrue(instance.isUidTempPowerSaveExempt(UID_10_2));
}
@Test
- public void testPowerSaveUserWhitelist() throws Exception {
+ public void testPowerSaveUserExemptionList() throws Exception {
final AppStateTrackerTestable instance = newInstance();
- instance.setPowerSaveWhitelistAppIds(new int[] {}, new int[] {UID_1, UID_2}, new int[] {});
- assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_1));
- assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_2));
- assertFalse(instance.isUidPowerSaveUserWhitelisted(UID_3));
+ instance.setPowerSaveExemptionListAppIds(new int[] {}, new int[] {UID_1, UID_2},
+ new int[] {});
+ assertTrue(instance.isUidPowerSaveUserExempt(UID_1));
+ assertTrue(instance.isUidPowerSaveUserExempt(UID_2));
+ assertFalse(instance.isUidPowerSaveUserExempt(UID_3));
}
@Test
@@ -909,9 +911,10 @@
reset(l);
// -------------------------------------------------------------------------
- // Tests with system/user/temp whitelist.
+ // Tests with system/user/temp exemption list.
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_1, UID_2}, new int[] {},
+ new int[] {});
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
@@ -923,7 +926,7 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
@@ -935,8 +938,8 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- // Update temp whitelist.
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+ // Update temp exemption list.
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
new int[] {UID_1, UID_3});
waitUntilMainHandlerDrain();
@@ -949,7 +952,8 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
+ new int[] {UID_3});
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
@@ -975,10 +979,11 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_1, UID_2}, new int[] {},
+ new int[] {});
waitUntilMainHandlerDrain();
- // Called once for updating all whitelist and once for updating temp whitelist
+ // Called once for updating all exemption list and once for updating temp exemption list
verify(l, times(2)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -988,7 +993,7 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
@@ -1000,8 +1005,8 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- // Update temp whitelist.
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+ // Update temp exemption list.
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
new int[] {UID_1, UID_3});
waitUntilMainHandlerDrain();
@@ -1014,7 +1019,8 @@
verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
reset(l);
- instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
+ instance.setPowerSaveExemptionListAppIds(new int[] {UID_2}, new int[] {},
+ new int[] {UID_3});
waitUntilMainHandlerDrain();
verify(l, times(1)).updateAllJobs();
@@ -1254,7 +1260,7 @@
.mapToInt(Integer::intValue).toArray();
}
- static boolean isAnyAppIdUnwhitelistedSlow(int[] prevArray, int[] newArray) {
+ static boolean isAnyAppIdUnexemptSlow(int[] prevArray, int[] newArray) {
Arrays.sort(newArray); // Just in case...
for (int p : prevArray) {
if (Arrays.binarySearch(newArray, p) < 0) {
@@ -1264,31 +1270,31 @@
return false;
}
- private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
+ private void checkAnyAppIdUnexempt(int[] prevArray, int[] newArray, boolean expected) {
assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
- expected, AppStateTrackerImpl.isAnyAppIdUnwhitelisted(prevArray, newArray));
+ expected, AppStateTrackerImpl.isAnyAppIdUnexempt(prevArray, newArray));
- // Also test isAnyAppIdUnwhitelistedSlow.
+ // Also test isAnyAppIdUnexempt.
assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
- expected, isAnyAppIdUnwhitelistedSlow(prevArray, newArray));
+ expected, isAnyAppIdUnexemptSlow(prevArray, newArray));
}
@Test
- public void isAnyAppIdUnwhitelisted() {
- checkAnyAppIdUnwhitelisted(array(), array(), false);
+ public void isAnyAppIdUnexempt() {
+ checkAnyAppIdUnexempt(array(), array(), false);
- checkAnyAppIdUnwhitelisted(array(1), array(), true);
- checkAnyAppIdUnwhitelisted(array(1), array(1), false);
- checkAnyAppIdUnwhitelisted(array(1), array(0, 1), false);
- checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
- checkAnyAppIdUnwhitelisted(array(1), array(0, 1, 2), false);
+ checkAnyAppIdUnexempt(array(1), array(), true);
+ checkAnyAppIdUnexempt(array(1), array(1), false);
+ checkAnyAppIdUnexempt(array(1), array(0, 1), false);
+ checkAnyAppIdUnexempt(array(1), array(0, 1, 2), false);
+ checkAnyAppIdUnexempt(array(1), array(0, 1, 2), false);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(), true);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2), true);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(1, 2, 10), false);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(2, 10), true);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 1, 2, 4, 3, 10), false);
- checkAnyAppIdUnwhitelisted(array(1, 2, 10), array(0, 0, 1, 2, 10), false);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(), true);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(1, 2), true);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(1, 2, 10), false);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(2, 10), true);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(0, 1, 2, 4, 3, 10), false);
+ checkAnyAppIdUnexempt(array(1, 2, 10), array(0, 0, 1, 2, 10), false);
// Random test
int trueCount = 0;
@@ -1297,8 +1303,8 @@
final int[] array1 = makeRandomArray();
final int[] array2 = makeRandomArray();
- final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
- final boolean actual = AppStateTrackerImpl.isAnyAppIdUnwhitelisted(array1, array2);
+ final boolean expected = isAnyAppIdUnexemptSlow(array1, array2);
+ final boolean actual = AppStateTrackerImpl.isAnyAppIdUnexempt(array1, array2);
assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
expected, actual);
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 6f37ff5..c91bb93 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -28,11 +28,13 @@
import android.app.StatusBarManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.os.Looper;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
+import android.telecom.TelecomManager;
import android.test.mock.MockContentResolver;
import android.util.MutableBoolean;
import android.view.KeyEvent;
@@ -80,6 +82,7 @@
private @Mock Context mContext;
private @Mock Resources mResources;
private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
+ private @Mock TelecomManager mTelecomManager;
private @Mock MetricsLogger mMetricsLogger;
private MockContentResolver mContentResolver;
private GestureLauncherService mGestureLauncherService;
@@ -104,6 +107,8 @@
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
+ when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent());
mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger);
}
@@ -176,6 +181,13 @@
}
@Test
+ public void testHandlePanicGesture_userSetupComplete() {
+ withUserSetupCompleteValue(true);
+
+ assertTrue(mGestureLauncherService.handlePanicButtonGesture());
+ }
+
+ @Test
public void testHandleCameraLaunchGesture_userSetupNotComplete() {
withUserSetupCompleteValue(false);
@@ -184,6 +196,13 @@
}
@Test
+ public void testHandlePanicGesture_userSetupNotComplete() {
+ withUserSetupCompleteValue(false);
+
+ assertFalse(mGestureLauncherService.handlePanicButtonGesture());
+ }
+
+ @Test
public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
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 0dfdd48..922d715 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -99,6 +99,7 @@
AttentionCheck attentionCheck = new AttentionCheck(mMockAttentionCallbackInternal,
mSpyAttentionManager);
mSpyAttentionManager.mCurrentAttentionCheck = attentionCheck;
+ mSpyAttentionManager.mService = new MockIAttentionService();
}
@Test
@@ -115,6 +116,7 @@
@Test
public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException {
+ doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
doReturn(false).when(mMockIPowerManager).isInteractive();
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse();
@@ -122,9 +124,11 @@
@Test
public void testCheckAttention_callOnSuccess() throws RemoteException {
- doReturn(true).when(mSpyAttentionManager).isServiceEnabled();
+ doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
doReturn(true).when(mMockIPowerManager).isInteractive();
doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
+ mSpyAttentionManager.mCurrentAttentionCheck = null;
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
mSpyAttentionManager.checkAttention(mTimeout, callback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
new file mode 100644
index 0000000..dad360d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class BiometricSchedulerTest {
+
+ private static final String TAG = "BiometricSchedulerTest";
+
+ private BiometricScheduler mScheduler;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private ClientMonitor.LazyDaemon<Object> mLazyDaemon;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
+ }
+
+ @Test
+ public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
+ final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, mLazyDaemon);
+ final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, mLazyDaemon);
+ mScheduler.scheduleClientMonitor(client1);
+ mScheduler.scheduleClientMonitor(client2);
+
+ client1.mFinishCallback.onClientFinished(client1, true /* success */);
+ client1.mFinishCallback.onClientFinished(client1, true /* success */);
+ }
+
+ private static class TestClientMonitor extends ClientMonitor<Object> {
+
+ public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
+ TAG, 0 /* cookie */, 0 /* sensorId */, 0 /* statsModality */,
+ 0 /* statsAction */, 0 /* statsClient */);
+ }
+
+ @Override
+ public void unableToStart() {
+
+ }
+
+ @Override
+ protected void startHalOperation() {
+
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 50086af..870a274 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -144,6 +144,26 @@
}
@Test
+ public void playbackDevice_updatesActiveSourceState() {
+ HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+ mHdmiControlService);
+ playbackDevice.init();
+ mLocalDevices.add(playbackDevice);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ HdmiCecFeatureAction action = new com.android.server.hdmi.ActiveSourceAction(
+ playbackDevice, ADDR_TV);
+ playbackDevice.addAndStartAction(action);
+ mTestLooper.dispatchAll();
+
+ assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
+ playbackDevice.mAddress);
+ assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
+ assertThat(playbackDevice.mIsActiveSource).isTrue();
+ }
+
+ @Test
public void audioDevice_sendsActiveSource_noMenuStatus() {
HdmiCecLocalDeviceAudioSystem audioDevice = new HdmiCecLocalDeviceAudioSystem(
mHdmiControlService);
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 35f9ca5..960a7ab 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -22,6 +23,7 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.hdmi.HdmiControlManager;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
@@ -29,6 +31,7 @@
import android.os.PowerManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings.Global;
import android.sysprop.HdmiProperties;
import android.view.KeyEvent;
@@ -272,7 +275,6 @@
}
@Test
- @Ignore("b/120845532")
public void handleSetSystemAudioModeOn_audioSystemBroadcast() {
mHdmiControlService.setSystemAudioActivated(false);
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse();
@@ -284,7 +286,6 @@
}
@Test
- @Ignore("b/120845532")
public void handleSetSystemAudioModeOff_audioSystemToPlayback() {
mHdmiCecLocalDevicePlayback.mService.setSystemAudioActivated(true);
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isTrue();
@@ -298,8 +299,7 @@
}
@Test
- @Ignore("b/120845532")
- public void handleSystemAudioModeStatusOn_DirectltToLocalDeviceFromAudioSystem() {
+ public void handleSystemAudioModeStatusOn_DirectlyToLocalDeviceFromAudioSystem() {
mHdmiControlService.setSystemAudioActivated(false);
assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse();
HdmiCecMessage message =
@@ -324,29 +324,117 @@
}
@Test
- public void handleOnStandby_ScreenOff_NotActiveSource() {
+ public void handleOnStandby_ScreenOff_NotActiveSource_ToTv() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
- assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessage);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
}
@Test
- public void handleOnStandby_ScreenOff_ActiveSource() {
+ public void handleOnStandby_ScreenOff_NotActiveSource_Broadcast() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_NotActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_ToTv() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
- assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_Broadcast() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
}
@Test
@@ -526,4 +614,19 @@
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
}
+
+ @Test
+ public void handleSetStreamPath_afterHotplug_hasCorrectActiveSource() {
+ mHdmiControlService.onHotplug(1, false);
+ mHdmiControlService.onHotplug(1, true);
+
+ HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
+ mPlaybackPhysicalAddress);
+ mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
index 6b7634d..62cc111 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
@@ -97,9 +97,9 @@
mJobSet.remove(testJob1);
mJobSet.remove(testJob2);
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
- mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId(), SECONDARY_USER_ID_1});
+ mJobSet.removeJobsOfUnlistedUsers(new int[] {mContext.getUserId(), SECONDARY_USER_ID_1});
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
- mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId()});
+ mJobSet.removeJobsOfUnlistedUsers(new int[] {mContext.getUserId()});
assertTrue("mJobs should be empty", mJobSet.mJobs.size() == 0);
assertTrue("mJobsPerSourceUid should be empty", mJobSet.mJobsPerSourceUid.size() == 0);
}
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 e08eea2..0839273 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -160,7 +160,7 @@
private val hasPermission: Boolean = false,
private val overlayableInfo: OverlayableInfo? = null,
private vararg val packageNames: String = arrayOf("com.test.actor.one")
- ) : OverlayableInfoCallback {
+ ) : PackageManagerHelper {
override fun getNamedActors() = if (isActor) {
mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
@@ -195,6 +195,14 @@
}
}
+ override fun getConfigSignaturePackage(): String {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getOverlayPackages(userId: Int): MutableList<PackageInfo> {
+ throw UnsupportedOperationException()
+ }
+
override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean {
throw UnsupportedOperationException()
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index b7692f9..e281f2b 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -44,9 +44,9 @@
@Test
public void testUpdateOverlaysForUser() {
final OverlayManagerServiceImpl impl = getImpl();
- addSystemPackage(target(TARGET), USER);
- addSystemPackage(target("some.other.target"), USER);;
- addSystemPackage(overlay(OVERLAY, TARGET), USER);
+ addPackage(target(TARGET), USER);
+ addPackage(target("some.other.target"), USER);
+ addPackage(overlay(OVERLAY, TARGET), USER);
// do nothing, expect no change
final List<String> a = impl.updateOverlaysForUser(USER);
@@ -54,7 +54,7 @@
assertTrue(a.contains(TARGET));
// upgrade overlay, keep target
- addSystemPackage(overlay(OVERLAY, TARGET), USER);
+ addPackage(overlay(OVERLAY, TARGET), USER);
final List<String> b = impl.updateOverlaysForUser(USER);
assertEquals(1, b.size());
@@ -66,7 +66,7 @@
assertTrue(c.contains(TARGET));
// upgrade overlay, switch to new target
- addSystemPackage(overlay(OVERLAY, "some.other.target"), USER);
+ addPackage(overlay(OVERLAY, "some.other.target"), USER);
final List<String> d = impl.updateOverlaysForUser(USER);
assertEquals(2, d.size());
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index f4c5506..c1d862a 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -19,6 +19,7 @@
import static android.content.om.OverlayInfo.STATE_DISABLED;
import static android.content.om.OverlayInfo.STATE_ENABLED;
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -49,6 +50,10 @@
private static final String OVERLAY3 = OVERLAY + "3";
private static final int USER3 = USER2 + 1;
+ private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref";
+ private static final String CERT_CONFIG_OK = "config_certificate_ok";
+ private static final String CERT_CONFIG_NOK = "config_certificate_nok";
+
@Test
public void testGetOverlayInfo() {
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -204,4 +209,87 @@
impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count);
}
+
+ @Test
+ public void testConfigSignaturePolicyOk() {
+ setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+ reinitializeImpl();
+
+ addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER);
+
+ final DummyIdmapDaemon idmapd = getIdmapd();
+ final DummyDeviceState state = getState();
+ String overlayPath = state.select(OVERLAY, USER).apkPath;
+ assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+ DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+ assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE);
+ }
+
+ @Test
+ public void testConfigSignaturePolicyCertNok() {
+ setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+ reinitializeImpl();
+
+ addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+ final DummyIdmapDaemon idmapd = getIdmapd();
+ final DummyDeviceState state = getState();
+ String overlayPath = state.select(OVERLAY, USER).apkPath;
+ assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+ DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+ assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+ }
+
+ @Test
+ public void testConfigSignaturePolicyNoConfig() {
+ addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+ final DummyIdmapDaemon idmapd = getIdmapd();
+ final DummyDeviceState state = getState();
+ String overlayPath = state.select(OVERLAY, USER).apkPath;
+ assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+ DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+ assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+ }
+
+ @Test
+ public void testConfigSignaturePolicyNoRefPkg() {
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+ final DummyIdmapDaemon idmapd = getIdmapd();
+ final DummyDeviceState state = getState();
+ String overlayPath = state.select(OVERLAY, USER).apkPath;
+ assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+ DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+ assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+ }
+
+ @Test
+ public void testConfigSignaturePolicyRefPkgNotSystem() {
+ setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
+ reinitializeImpl();
+
+ addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
+ installNewPackage(target(TARGET), USER);
+ installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
+
+ final DummyIdmapDaemon idmapd = getIdmapd();
+ final DummyDeviceState state = getState();
+ String overlayPath = state.select(OVERLAY, USER).apkPath;
+ assertTrue(idmapd.idmapExists(overlayPath, USER));
+
+ DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
+ assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 733310b..2faf29f 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -27,6 +27,7 @@
import android.content.om.OverlayableInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -52,6 +53,7 @@
private DummyPackageManagerHelper mPackageManager;
private DummyIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
+ private String mConfigSignaturePackageName;
@Before
public void setUp() {
@@ -83,6 +85,18 @@
return mListener;
}
+ DummyIdmapDaemon getIdmapd() {
+ return mIdmapDaemon;
+ }
+
+ DummyDeviceState getState() {
+ return mState;
+ }
+
+ void setConfigSignaturePackageName(String packageName) {
+ mConfigSignaturePackageName = packageName;
+ }
+
void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) {
@@ -102,9 +116,14 @@
assertEquals(expected, actual);
}
+ DummyDeviceState.PackageBuilder app(String packageName) {
+ return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
+ null /* targetOverlayableName */, "data");
+ }
+
DummyDeviceState.PackageBuilder target(String packageName) {
return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
- null /* targetOverlayableName */);
+ null /* targetOverlayableName */, "");
}
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
@@ -114,10 +133,10 @@
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
String targetOverlayableName) {
return new DummyDeviceState.PackageBuilder(packageName, targetPackageName,
- targetOverlayableName);
+ targetOverlayableName, "");
}
- void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
+ void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) {
mState.add(pkg, userId);
}
@@ -242,15 +261,17 @@
private String packageName;
private String targetPackage;
private String certificate = "[default]";
+ private String partition;
private int version = 0;
private ArrayList<String> overlayableNames = new ArrayList<>();
private String targetOverlayableName;
private PackageBuilder(String packageName, String targetPackage,
- String targetOverlayableName) {
+ String targetOverlayableName, String partition) {
this.packageName = packageName;
this.targetPackage = targetPackage;
this.targetOverlayableName = targetOverlayableName;
+ this.partition = partition;
}
PackageBuilder setCertificate(String certificate) {
@@ -269,9 +290,19 @@
}
Package build() {
- final String apkPath = String.format("%s/%s/base.apk",
- targetPackage == null ? "/system/app/:" : "/vendor/overlay/:",
- packageName);
+ String path = "";
+ if (TextUtils.isEmpty(partition)) {
+ if (targetPackage == null) {
+ path = "/system/app";
+ } else {
+ path = "/vendor/overlay";
+ }
+ } else {
+ String type = targetPackage == null ? "app" : "overlay";
+ path = String.format("%s/%s", partition, type);
+ }
+
+ final String apkPath = String.format("%s/%s/base.apk", path, packageName);
final Package newPackage = new Package(packageName, targetPackage,
targetOverlayableName, version, apkPath, certificate);
newPackage.overlayableNames.addAll(overlayableNames);
@@ -302,8 +333,7 @@
}
}
- static final class DummyPackageManagerHelper implements PackageManagerHelper,
- OverlayableInfoCallback {
+ final class DummyPackageManagerHelper implements PackageManagerHelper {
private final DummyDeviceState mState;
private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -343,6 +373,11 @@
.collect(Collectors.toList());
}
+ @Override
+ public @NonNull String getConfigSignaturePackage() {
+ return mConfigSignaturePackageName;
+ }
+
@Nullable
@Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index 78c7080..d888b92 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -25,7 +25,6 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
-import org.testng.Assert.assertThrows
@RunWith(Parameterized::class)
class OverlayReferenceMapperTests {
@@ -160,9 +159,6 @@
expected.forEach { (actorPkgName, expectedPkgNames) ->
expectedPkgNames.forEach { expectedPkgName ->
if (deferRebuild) {
- assertThrows(IllegalStateException::class.java) {
- mapper.isValidActor(expectedPkgName, actorPkgName)
- }
mapper.rebuildIfDeferred()
deferRebuild = false
}
@@ -187,7 +183,7 @@
)
)
) = OverlayReferenceMapper(deferRebuild, object : OverlayReferenceMapper.Provider {
- override fun getActorPkg(actor: String?) =
+ override fun getActorPkg(actor: String) =
OverlayActorEnforcer.getPackageNameForActor(actor, namedActors).first
override fun getTargetToOverlayables(pkg: AndroidPackage) =
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 2d9c6ce..f991dff 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -19,7 +19,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -70,8 +69,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.IntFunction;
-import java.util.stream.Collectors;
@Presubmit
@RunWith(JUnit4.class)
@@ -805,24 +802,24 @@
queriesProviderAppId);
final SparseArray<int[]> systemFilter =
- appsFilter.getVisibilityWhitelist(system, USER_ARRAY, mExisting);
+ appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
assertThat(toList(systemFilter.get(SYSTEM_USER)),
contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
final SparseArray<int[]> seesNothingFilter =
- appsFilter.getVisibilityWhitelist(seesNothing, USER_ARRAY, mExisting);
+ appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
contains(seesNothingAppId));
assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
contains(seesNothingAppId));
final SparseArray<int[]> hasProviderFilter =
- appsFilter.getVisibilityWhitelist(hasProvider, USER_ARRAY, mExisting);
+ appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
contains(hasProviderAppId, queriesProviderAppId));
SparseArray<int[]> queriesProviderFilter =
- appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+ appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
contains(queriesProviderAppId));
@@ -831,7 +828,7 @@
// ensure implicit access is included in the filter
queriesProviderFilter =
- appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+ appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
contains(hasProviderAppId, queriesProviderAppId));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index fa9ee19..aa92ba4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -57,6 +57,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
import com.android.server.pm.permission.PermissionSettings;
@@ -86,6 +87,8 @@
@Mock
PermissionSettings mPermissionSettings;
+ @Mock
+ RuntimePermissionsPersistence mRuntimePermissionsPersistence;
@Before
public void initializeMocks() {
@@ -106,7 +109,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}
@@ -119,7 +123,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// write out, read back in and verify the same
@@ -134,7 +139,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
@@ -155,12 +161,14 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
settings.writeLPr();
// Create Settings again to make it read from the new files
- settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
@@ -183,7 +191,7 @@
writePackageRestrictions_noSuspendingPackageXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -206,7 +214,7 @@
writePackageRestrictions_noSuspendParamsMapXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -233,7 +241,8 @@
@Test
public void testReadWritePackageRestrictions_suspendInfo() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -330,7 +339,8 @@
@Test
public void testReadWritePackageRestrictions_distractionFlags() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -381,7 +391,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// Enable/Disable a package
@@ -558,8 +569,8 @@
public void testUpdatePackageSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- final Settings testSettings01 =
- new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 =
@@ -673,8 +684,8 @@
public void testCreateNewSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- final Settings testSettings01 =
- new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 = Settings.createNewSetting(
diff --git a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
index a1f1056..2230ddd 100644
--- a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
@@ -72,21 +72,32 @@
@Test
public void testSystemServerEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal();
+ mInstance.recordCheckPointInternal("reason1");
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServerEntry\n at "));
}
@Test
- public void testSystemServiceBinderEntry() {
+ public void testSystemServerEntryWithoutReason() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(Process.myPid());
+ mInstance.recordCheckPointInternal(null);
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
+ public void testSystemServiceBinderEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(Process.myPid(), "reason1");
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServiceBinderEntry\n at "));
}
@@ -99,10 +110,11 @@
when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos);
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testCallerProcessBinderEntry\n"
+ "From process process_name (pid=1)\n\n",
@@ -114,10 +126,11 @@
when(mActivityManager.getRunningAppProcesses()).thenThrow(new RemoteException("Error"));
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testRemoteExceptionOnBinderEntry\n"
+ "From process ? (pid=1)\n\n",
@@ -127,10 +140,11 @@
@Test
public void testUnknownProcessBinderEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testUnknownProcessBinderEntry\n"
+ "From process ? (pid=1)\n\n",
@@ -138,12 +152,22 @@
}
@Test
- public void testSystemServiceIntentEntry() {
+ public void testBinderEntryWithoutReason() throws RemoteException {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("some.intent", "android");
+ mInstance.recordCheckPointInternal(1, null);
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
+ public void testSystemServiceIntentEntry() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "android", "reason1");
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServiceIntentEntry\n at "));
}
@@ -151,39 +175,47 @@
@Test
public void testIntentEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("some.intent", "some.app");
+ mInstance.recordCheckPointInternal("some.intent", "some.app", "reason1");
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: some.intent\n"
+ "Package: some.app\n\n",
dumpToString());
}
@Test
+ public void testIntentEntryWithoutReason() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "some.app", null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
public void testMultipleEntries() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
mTestInjector.setCurrentTime(2000);
- mInstance.recordCheckPointInternal(2);
+ mInstance.recordCheckPointInternal(2, "reason2");
mTestInjector.setCurrentTime(3000);
- mInstance.recordCheckPointInternal("intent", "app");
+ mInstance.recordCheckPointInternal("intent", "app", "reason3");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
- + "From process ? (pid=1)\n"
- + "\n"
- + "Shutdown request from BINDER at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "From process ? (pid=1)\n\n"
+ + "Shutdown request from BINDER for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
- + "From process ? (pid=2)\n"
- + "\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:03.000 UTC (epoch=3000)"
- + "\n"
+ + "From process ? (pid=2)\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ "Intent: intent\n"
- + "Package: app\n"
- + "\n",
+ + "Package: app\n\n",
dumpToString());
}
@@ -193,23 +225,22 @@
ShutdownCheckPoints limitedInstance = new ShutdownCheckPoints(mTestInjector);
mTestInjector.setCurrentTime(1000);
- limitedInstance.recordCheckPointInternal("intent.1", "app.1");
+ limitedInstance.recordCheckPointInternal("intent.1", "app.1", "reason1");
mTestInjector.setCurrentTime(2000);
- limitedInstance.recordCheckPointInternal("intent.2", "app.2");
+ limitedInstance.recordCheckPointInternal("intent.2", "app.2", "reason2");
mTestInjector.setCurrentTime(3000);
- limitedInstance.recordCheckPointInternal("intent.3", "app.3");
+ limitedInstance.recordCheckPointInternal("intent.3", "app.3", "reason3");
// Drops first intent.
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: intent.2\n"
- + "Package: app.2\n"
- + "\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:03.000 UTC (epoch=3000)"
- + "\n"
+ + "Package: app.2\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ "Intent: intent.3\n"
- + "Package: app.3\n"
- + "\n",
+ + "Package: app.3\n\n",
dumpToString(limitedInstance));
}
@@ -219,11 +250,11 @@
File baseFile = new File(tempDir, "checkpoints");
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("first.intent", "first.app");
+ mInstance.recordCheckPointInternal("first.intent", "first.app", "reason1");
dumpToFile(baseFile);
mTestInjector.setCurrentTime(2000);
- mInstance.recordCheckPointInternal("second.intent", "second.app");
+ mInstance.recordCheckPointInternal("second.intent", "second.app", "reason2");
dumpToFile(baseFile);
File[] dumpFiles = tempDir.listFiles();
@@ -231,16 +262,18 @@
assertEquals(2, dumpFiles.length);
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n",
readFileAsString(dumpFiles[0].getAbsolutePath()));
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: second.intent\n"
+ "Package: second.app\n\n",
readFileAsString(dumpFiles[1].getAbsolutePath()));
@@ -254,21 +287,22 @@
File baseFile = new File(tempDir, "checkpoints");
mTestInjector.setCurrentTime(1000);
- instance.recordCheckPointInternal("first.intent", "first.app");
+ instance.recordCheckPointInternal("first.intent", "first.app", "reason1");
dumpToFile(instance, baseFile);
mTestInjector.setCurrentTime(2000);
- instance.recordCheckPointInternal("second.intent", "second.app");
+ instance.recordCheckPointInternal("second.intent", "second.app", "reason2");
dumpToFile(instance, baseFile);
File[] dumpFiles = tempDir.listFiles();
assertEquals(1, dumpFiles.length);
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: second.intent\n"
+ "Package: second.app\n\n",
readFileAsString(dumpFiles[0].getAbsolutePath()));
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 10976882..980772b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -166,6 +166,7 @@
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.UiServiceTestCase;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
@@ -178,7 +179,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -3774,6 +3774,27 @@
}
@Test
+ public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception {
+ final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel);
+ final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
+ mService.addEnqueuedNotification(r1);
+ mService.addEnqueuedNotification(r2);
+ when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
+
+ Bundle signals = new Bundle();
+ signals.putInt(Adjustment.KEY_IMPORTANCE,
+ IMPORTANCE_HIGH);
+ Adjustment adjustment = new Adjustment(
+ r1.getSbn().getPackageName(), r1.getKey(), signals,
+ "", r1.getUser().getIdentifier());
+
+ mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
+
+ assertEquals(IMPORTANCE_HIGH, r1.getImportance());
+ assertEquals(IMPORTANCE_HIGH, r2.getImportance());
+ }
+
+ @Test
public void testRestore() throws Exception {
int systemChecks = mService.countSystemChecks;
mBinderService.applyRestore(null, USER_SYSTEM);
@@ -6434,7 +6455,7 @@
public void testOnUnlockUser() {
UserInfo ui = new UserInfo();
ui.id = 10;
- mService.onUnlockUser(ui);
+ mService.onUserUnlocking(new TargetUser(ui));
waitForIdle();
verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
@@ -6444,7 +6465,7 @@
public void testOnStopUser() {
UserInfo ui = new UserInfo();
ui.id = 10;
- mService.onStopUser(ui);
+ mService.onUserStopping(new TargetUser(ui));
waitForIdle();
verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e45ced6..2f02073 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1327,12 +1327,15 @@
public void testRemoveFromHistory() {
final Task stack = mActivity.getRootTask();
final Task task = mActivity.getTask();
+ final WindowProcessController wpc = mActivity.app;
+ assertTrue(wpc.hasActivities());
mActivity.removeFromHistory("test");
assertEquals(DESTROYED, mActivity.getState());
assertNull(mActivity.app);
assertNull(mActivity.getTask());
+ assertFalse(wpc.hasActivities());
assertEquals(0, task.getChildCount());
assertEquals(task.getRootTask(), task);
assertEquals(0, stack.getChildCount());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 775df74..dfdf686 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1072,7 +1072,7 @@
assertEquals(2, mTask.getChildCount());
- mRootWindowContainer.handleAppDied(secondActivity.app);
+ secondActivity.app.handleAppDied();
assertFalse(mTask.hasChild());
assertFalse(mStack.hasChild());
@@ -1086,7 +1086,7 @@
activity.launchCount = 1;
activity.setSavedState(null /* savedState */);
- mRootWindowContainer.handleAppDied(activity.app);
+ activity.app.handleAppDied();
assertEquals(1, mTask.getChildCount());
assertEquals(1, mStack.getChildCount());
@@ -1100,7 +1100,7 @@
activity.launchCount = 3;
activity.setSavedState(null /* savedState */);
- mRootWindowContainer.handleAppDied(activity.app);
+ activity.app.handleAppDied();
assertFalse(mTask.hasChild());
assertFalse(mStack.hasChild());
@@ -1114,7 +1114,7 @@
activity.launchCount = 1;
activity.setSavedState(null /* savedState */);
- mRootWindowContainer.handleAppDied(activity.app);
+ activity.app.handleAppDied();
assertEquals(1, mTask.getChildCount());
assertEquals(1, mStack.getChildCount());
@@ -1128,7 +1128,7 @@
activity.launchCount = 3;
activity.setSavedState(null /* savedState */);
- mRootWindowContainer.handleAppDied(activity.app);
+ activity.app.handleAppDied();
assertFalse(mTask.hasChild());
assertFalse(mStack.hasChild());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index d7baf8d..7adcead 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -129,36 +129,6 @@
}
@Test
- public void testGetAnimationTargets_noHierarchicalAnimations() {
- WindowManagerService.sHierarchicalAnimations = false;
-
- // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, invisible)
- // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, visible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1);
- activity1.setVisible(false);
- activity1.mVisibleRequested = true;
-
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2);
-
- final ArraySet<ActivityRecord> opening = new ArraySet<>();
- opening.add(activity1);
- final ArraySet<ActivityRecord> closing = new ArraySet<>();
- closing.add(activity2);
-
- // Don't promote when the flag is disabled.
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity2}),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
- }
-
- @Test
public void testGetAnimationTargets_visibilityAlreadyUpdated() {
// [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible)
// +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible)
@@ -177,17 +147,6 @@
// No animation, since visibility of the opening and closing apps are already updated
// outside of AppTransition framework.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(),
AppTransitionController.getAnimationTargets(
@@ -221,13 +180,12 @@
// The visibility are already updated, but since forced transition is requested, it will
// be included.
- WindowManagerService.sHierarchicalAnimations = false;
assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getStack()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
- new ArraySet<>(new WindowContainer[]{activity2}),
+ new ArraySet<>(new WindowContainer[]{activity2.getStack()}),
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
@@ -247,13 +205,6 @@
// Animate closing apps even if it's not visible when it is exiting before we had a chance
// to play the transition animation.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity}),
- AppTransitionController.getAnimationTargets(
- new ArraySet<>(), closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(new WindowContainer[]{stack}),
AppTransitionController.getAnimationTargets(
@@ -292,17 +243,6 @@
// Animate opening apps even if it's already visible in case its windows are being replaced.
// Don't animate closing apps if it's already invisible even though its windows are being
// replaced.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(new WindowContainer[]{}),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(new WindowContainer[]{stack1}),
AppTransitionController.getAnimationTargets(
@@ -315,8 +255,6 @@
@Test
public void testGetAnimationTargets_openingClosingInDifferentTask() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (invisible)
// |
@@ -361,8 +299,6 @@
@Test
public void testGetAnimationTargets_openingClosingInSameTask() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] - [TaskStack] - [Task] -+- [ActivityRecord1] (opening, invisible)
// +- [ActivityRecord2] (closing, visible)
final Task stack = createTaskStackOnDisplay(mDisplayContent);
@@ -393,8 +329,6 @@
@Test
public void testGetAnimationTargets_animateOnlyTranslucentApp() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (visible)
// |
@@ -439,8 +373,6 @@
@Test
public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (opening, invisible)
// |
@@ -489,8 +421,6 @@
@Test
public void testGetAnimationTargets_stackContainsMultipleTasks() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] - [TaskStack] -+- [Task1] - [ActivityRecord1] (opening, invisible)
// +- [Task2] - [ActivityRecord2] (closing, visible)
final Task stack = createTaskStackOnDisplay(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index bcd93715..5828d02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -33,6 +33,7 @@
import static org.junit.Assert.assertTrue;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -324,6 +325,47 @@
assertEquals(100, listener.mOverrideConfiguration.smallestScreenWidthDp);
}
+ @Test
+ public void testSetMaxBoundsByHierarchy() {
+ final TestConfigurationContainer root =
+ new TestConfigurationContainer(true /* providesMaxBounds */);
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final TestConfigurationContainer child = new TestConfigurationContainer();
+ root.addChild(child);
+
+ root.setBounds(bounds);
+
+ assertEquals(bounds, root.getBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+ assertEquals(bounds, child.getBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+ assertEquals(bounds, root.getMaxBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getMaxBounds());
+ assertEquals(bounds, child.getMaxBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getMaxBounds());
+ }
+
+ @Test
+ public void testSetBoundsNotOverrideMaxBounds() {
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final TestConfigurationContainer child = new TestConfigurationContainer();
+ root.addChild(child);
+
+ root.setBounds(bounds);
+
+ assertEquals(bounds, root.getBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+ assertEquals(bounds, child.getBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+ assertTrue(root.getMaxBounds().isEmpty());
+ assertTrue(root.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
+ assertTrue(child.getMaxBounds().isEmpty());
+ assertTrue(child.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
+ }
+
/**
* Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
* for testing.
@@ -333,6 +375,14 @@
private List<TestConfigurationContainer> mChildren = new ArrayList<>();
private TestConfigurationContainer mParent;
+ private boolean mProvidesMaxBounds = false;
+
+ TestConfigurationContainer() {}
+
+ TestConfigurationContainer(boolean providesMaxBounds) {
+ mProvidesMaxBounds = providesMaxBounds;
+ }
+
TestConfigurationContainer addChild(TestConfigurationContainer childContainer) {
final ConfigurationContainer oldParent = childContainer.getParent();
childContainer.mParent = this;
@@ -369,6 +419,11 @@
protected ConfigurationContainer getParent() {
return mParent;
}
+
+ @Override
+ public boolean providesMaxBounds() {
+ return mProvidesMaxBounds;
+ }
}
/**
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 c8ed87d..e17601e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -40,8 +41,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.graphics.Rect;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
import com.google.android.collect.Lists;
@@ -63,7 +66,6 @@
*/
@Presubmit
public class DisplayAreaTest {
-
@Rule
public SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
@@ -379,6 +381,42 @@
assertThat(result).isEqualTo(tda1);
}
+ @Test
+ public void testSetMaxBounds() {
+ final Rect parentBounds = new Rect(0, 0, 100, 100);
+ final Rect childBounds1 = new Rect(parentBounds.left, parentBounds.top,
+ parentBounds.right / 2, parentBounds.bottom);
+ final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
+ parentBounds.right, parentBounds.bottom);
+ TestDisplayArea parentDa = new TestDisplayArea(mWms, parentBounds);
+ TestDisplayArea childDa1 = new TestDisplayArea(mWms, childBounds1);
+ TestDisplayArea childDa2 = new TestDisplayArea(mWms, childBounds2);
+ parentDa.addChild(childDa1, 0);
+ parentDa.addChild(childDa2, 1);
+
+ assertEquals(parentBounds, parentDa.getMaxBounds());
+ assertEquals(childBounds1, childDa1.getMaxBounds());
+ assertEquals(childBounds2, childDa2.getMaxBounds());
+
+ final WindowToken windowToken = createWindowToken(TYPE_APPLICATION);
+ childDa1.addChild(windowToken, 0);
+
+ assertEquals("DisplayArea's children must have the same max bounds as itself",
+ childBounds1, windowToken.getMaxBounds());
+ }
+
+ private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
+ private TestDisplayArea(WindowManagerService wms, Rect bounds) {
+ super(wms, ANY, "half display area");
+ setBounds(bounds);
+ }
+
+ @Override
+ SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+ return new MockSurfaceControlBuilder();
+ }
+ }
+
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/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 96ea646..edf1536 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1354,7 +1354,7 @@
assertFalse(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is finished.
- mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false);
+ mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
assertTrue(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is animating but it is not on top, e.g.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 695a0e3..8bc8c0b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -362,13 +362,14 @@
assertFalse(homeActivity.hasFixedRotationTransform());
}
- @Test
- public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
- unblockDisplayRotation(mDefaultDisplay);
+ private ActivityRecord prepareFixedRotationLaunchingAppWithRecentsAnim() {
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ // Add a window so it can be animated by the recents.
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+ activity.addWindow(win);
// Assume an activity is launching to different rotation.
mDefaultDisplay.setFixedRotationLaunchingApp(activity,
(mDefaultDisplay.getRotation() + 1) % 4);
@@ -379,6 +380,14 @@
// Before the transition is done, the recents animation is triggered.
initializeRecentsAnimationController(mController, homeActivity);
assertFalse(homeActivity.hasFixedRotationTransform());
+ assertTrue(mController.isAnimatingTask(activity.getTask()));
+
+ return activity;
+ }
+
+ @Test
+ public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
+ final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
// Simulate giving up the swipe up gesture to keep the original activity as top.
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
@@ -388,6 +397,21 @@
}
@Test
+ public void testKeepFixedRotationWhenMovingRecentsToTop() {
+ final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
+ // Assume a transition animation has started running before recents animation. Then the
+ // activity will receive onAnimationFinished that notifies app transition finished when
+ // removing the recents animation of task.
+ activity.getTask().getAnimationSources().add(activity);
+
+ // Simulate swiping to home/recents before the transition is done.
+ mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+ // The rotation transform should be preserved. In real case, it will be cleared by the next
+ // move-to-top transition.
+ assertTrue(activity.hasFixedRotationTransform());
+ }
+
+ @Test
public void testWallpaperHasFixedRotationApplied() {
unblockDisplayRotation(mDefaultDisplay);
mWm.setRecentsAnimationController(mController);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 2e4c9ea..d9d07d9b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -175,23 +175,30 @@
@Test
public void testForceStopPackage() {
final Task task = new ActivityTestsBase.StackBuilder(mWm.mRoot).build();
- final ActivityRecord activity1 = task.getTopMostActivity();
- final ActivityRecord activity2 =
- new ActivityTestsBase.ActivityBuilder(mWm.mAtmService).setStack(task).build();
- final WindowProcessController wpc = activity1.app;
+ final ActivityRecord activity = task.getTopMostActivity();
+ final WindowProcessController wpc = activity.app;
+ final ActivityRecord[] activities = {
+ activity,
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(task).setUseProcess(wpc).build(),
+ new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(task).setUseProcess(wpc).build()
+ };
+ activities[0].detachFromProcess();
+ activities[1].finishing = true;
+ activities[1].destroyImmediately(true /* removeFromApp */, "test");
spyOn(wpc);
- activity1.app = null;
- activity2.setProcess(wpc);
doReturn(true).when(wpc).isRemoved();
mWm.mAtmService.mInternal.onForceStopPackage(wpc.mInfo.packageName, true /* doit */,
false /* evenPersistent */, wpc.mUserId);
// The activity without process should be removed.
- assertEquals(1, task.getChildCount());
+ assertEquals(2, task.getChildCount());
- mWm.mRoot.handleAppDied(wpc);
- // The activity with process should be removed because WindowProcessController#isRemoved.
+ wpc.handleAppDied();
+ // The activities with process should be removed because WindowProcessController#isRemoved.
assertFalse(task.hasChild());
+ assertFalse(wpc.hasActivities());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index e8a4e90..75ed928 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -79,6 +79,16 @@
}
@Test
+ public void testRemoveFinishingInvisibleActivityFromUnknown() {
+ final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent);
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
+ activity.finishing = true;
+ activity.mVisibleRequested = true;
+ activity.setVisibility(false, false);
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
+ }
+
+ @Test
public void testAppRemoved() {
final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity);
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 6861ad1..4986d18 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -307,7 +307,7 @@
}
} else {
if (mActives > mObserved.length) {
- // Try to get to a sane state and log the issue
+ // Try to get to a valid state and log the issue
mActives = mObserved.length;
final UserData user = mUserRef.get();
if (user == null) return;
@@ -334,7 +334,7 @@
cancelCheckTimeoutLocked(this);
} else {
if (mActives < 0) {
- // Try to get to a sane state and log the issue
+ // Try to get to a valid state and log the issue
mActives = 0;
final UserData user = mUserRef.get();
if (user == null) return;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9b18ec6..2fd6c42 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -92,6 +92,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import java.io.BufferedReader;
@@ -291,27 +292,26 @@
}
@Override
- public void onStartUser(UserInfo userInfo) {
+ public void onUserStarting(@NonNull TargetUser user) {
// Create an entry in the user state map to indicate that the user has been started but
// not necessarily unlocked. This will ensure that reported events are flushed to disk
// event if the user is never unlocked (following the logic in #flushToDiskLocked)
- mUserState.put(userInfo.id, null);
- super.onStartUser(userInfo);
+ mUserState.put(user.getUserIdentifier(), null);
}
@Override
- public void onUnlockUser(@NonNull UserInfo userInfo) {
- mHandler.obtainMessage(MSG_UNLOCKED_USER, userInfo.id, 0).sendToTarget();
- super.onUnlockUser(userInfo);
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ mHandler.obtainMessage(MSG_UNLOCKED_USER, user.getUserIdentifier(), 0).sendToTarget();
}
@Override
- public void onStopUser(@NonNull UserInfo userInfo) {
+ public void onUserStopping(@NonNull TargetUser user) {
+ final UserInfo userInfo = user.getUserInfo();
+
synchronized (mLock) {
// User was started but never unlocked so no need to report a user stopped event
if (!mUserUnlockedStates.get(userInfo.id)) {
persistPendingEventsLocked(userInfo.id);
- super.onStopUser(userInfo);
return;
}
@@ -326,7 +326,6 @@
mUserUnlockedStates.put(userInfo.id, false);
mUserState.put(userInfo.id, null); // release the service (mainly for GC)
}
- super.onStopUser(userInfo);
}
private void onUserUnlocked(int userId) {
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 5239d97..22629dd 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -64,7 +64,7 @@
private UsbAlsaDevice mSelectedDevice;
//
- // Device Blacklist
+ // Device Denylist
//
// This exists due to problems with Sony game controllers which present as an audio device
// even if no headset is connected and have no way to set the volume on the unit.
@@ -73,31 +73,31 @@
private static final int USB_PRODUCTID_PS4CONTROLLER_ZCT1 = 0x05C4;
private static final int USB_PRODUCTID_PS4CONTROLLER_ZCT2 = 0x09CC;
- private static final int USB_BLACKLIST_OUTPUT = 0x0001;
- private static final int USB_BLACKLIST_INPUT = 0x0002;
+ private static final int USB_DENYLIST_OUTPUT = 0x0001;
+ private static final int USB_DENYLIST_INPUT = 0x0002;
- private static class BlackListEntry {
+ private static class DenyListEntry {
final int mVendorId;
final int mProductId;
final int mFlags;
- BlackListEntry(int vendorId, int productId, int flags) {
+ DenyListEntry(int vendorId, int productId, int flags) {
mVendorId = vendorId;
mProductId = productId;
mFlags = flags;
}
}
- static final List<BlackListEntry> sDeviceBlacklist = Arrays.asList(
- new BlackListEntry(USB_VENDORID_SONY,
+ static final List<DenyListEntry> sDeviceDenylist = Arrays.asList(
+ new DenyListEntry(USB_VENDORID_SONY,
USB_PRODUCTID_PS4CONTROLLER_ZCT1,
- USB_BLACKLIST_OUTPUT),
- new BlackListEntry(USB_VENDORID_SONY,
+ USB_DENYLIST_OUTPUT),
+ new DenyListEntry(USB_VENDORID_SONY,
USB_PRODUCTID_PS4CONTROLLER_ZCT2,
- USB_BLACKLIST_OUTPUT));
+ USB_DENYLIST_OUTPUT));
- private static boolean isDeviceBlacklisted(int vendorId, int productId, int flags) {
- for (BlackListEntry entry : sDeviceBlacklist) {
+ private static boolean isDeviceDenylisted(int vendorId, int productId, int flags) {
+ for (DenyListEntry entry : sDeviceDenylist) {
if (entry.mVendorId == vendorId && entry.mProductId == productId) {
// see if the type flag is set
return (entry.mFlags & flags) != 0;
@@ -226,11 +226,11 @@
// Add it to the devices list
boolean hasInput = parser.hasInput()
- && !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
- USB_BLACKLIST_INPUT);
+ && !isDeviceDenylisted(usbDevice.getVendorId(), usbDevice.getProductId(),
+ USB_DENYLIST_INPUT);
boolean hasOutput = parser.hasOutput()
- && !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
- USB_BLACKLIST_OUTPUT);
+ && !isDeviceDenylisted(usbDevice.getVendorId(), usbDevice.getProductId(),
+ USB_DENYLIST_OUTPUT);
if (DEBUG) {
Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput);
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 6cf0eec..2269e1d 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -201,22 +201,22 @@
private String[] mAccessoryStrings;
private final UEventObserver mUEventObserver;
- private static Set<Integer> sBlackListedInterfaces;
+ private static Set<Integer> sDenyInterfaces;
private HashMap<Long, FileDescriptor> mControlFds;
static {
- sBlackListedInterfaces = new HashSet<>();
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_COMM);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_HID);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_HUB);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CSCID);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
+ sDenyInterfaces = new HashSet<>();
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_COMM);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_HID);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_HUB);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CSCID);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
}
/*
@@ -960,7 +960,7 @@
while (interfaceCount >= 0) {
UsbInterface intrface = config.getInterface(interfaceCount);
interfaceCount--;
- if (sBlackListedInterfaces.contains(intrface.getInterfaceClass())) {
+ if (sDenyInterfaces.contains(intrface.getInterfaceClass())) {
mHideUsbNotification = true;
break;
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 140a95d..f33001c 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -62,7 +62,7 @@
private final Context mContext;
// USB busses to exclude from USB host support
- private final String[] mHostBlacklist;
+ private final String[] mHostDenyList;
private final UsbAlsaManager mUsbAlsaManager;
private final UsbPermissionManager mPermissionManager;
@@ -235,8 +235,8 @@
UsbPermissionManager permissionManager) {
mContext = context;
- mHostBlacklist = context.getResources().getStringArray(
- com.android.internal.R.array.config_usbHostBlacklist);
+ mHostDenyList = context.getResources().getStringArray(
+ com.android.internal.R.array.config_usbHostDenylist);
mUsbAlsaManager = alsaManager;
mPermissionManager = permissionManager;
String deviceConnectionHandler = context.getResources().getString(
@@ -271,10 +271,10 @@
}
}
- private boolean isBlackListed(String deviceAddress) {
- int count = mHostBlacklist.length;
+ private boolean isDenyListed(String deviceAddress) {
+ int count = mHostDenyList.length;
for (int i = 0; i < count; i++) {
- if (deviceAddress.startsWith(mHostBlacklist[i])) {
+ if (deviceAddress.startsWith(mHostDenyList[i])) {
return true;
}
}
@@ -282,11 +282,11 @@
}
/* returns true if the USB device should not be accessible by applications */
- private boolean isBlackListed(int clazz, int subClass) {
- // blacklist hubs
+ private boolean isDenyListed(int clazz, int subClass) {
+ // deny hubs
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
- // blacklist HID boot devices (mouse and keyboard)
+ // deny HID boot devices (mouse and keyboard)
return clazz == UsbConstants.USB_CLASS_HID
&& subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT;
@@ -355,23 +355,23 @@
Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
- if (isBlackListed(deviceAddress)) {
+ if (isDenyListed(deviceAddress)) {
if (DEBUG) {
- Slog.d(TAG, "device address is black listed");
+ Slog.d(TAG, "device address is Deny listed");
}
return false;
}
- if (isBlackListed(deviceClass, deviceSubclass)) {
+ if (isDenyListed(deviceClass, deviceSubclass)) {
if (DEBUG) {
- Slog.d(TAG, "device class is black listed");
+ Slog.d(TAG, "device class is deny listed");
}
return false;
}
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE
- && !checkUsbInterfacesBlackListed(parser)) {
+ && !checkUsbInterfacesDenyListed(parser)) {
return false;
}
@@ -491,12 +491,12 @@
public ParcelFileDescriptor openDevice(String deviceAddress,
UsbUserPermissionManager permissions, String packageName, int pid, int uid) {
synchronized (mLock) {
- if (isBlackListed(deviceAddress)) {
+ if (isDenyListed(deviceAddress)) {
throw new SecurityException("USB device is on a restricted bus");
}
UsbDevice device = mDevices.get(deviceAddress);
if (device == null) {
- // if it is not in mDevices, it either does not exist or is blacklisted
+ // if it is not in mDevices, it either does not exist or is denylisted
throw new IllegalArgumentException(
"device " + deviceAddress + " does not exist or is restricted");
}
@@ -554,23 +554,23 @@
}
}
- private boolean checkUsbInterfacesBlackListed(UsbDescriptorParser parser) {
+ private boolean checkUsbInterfacesDenyListed(UsbDescriptorParser parser) {
// Device class needs to be obtained through the device interface. Ignore device only
- // if ALL interfaces are black-listed.
+ // if ALL interfaces are deny-listed.
boolean shouldIgnoreDevice = false;
for (UsbDescriptor descriptor: parser.getDescriptors()) {
if (!(descriptor instanceof UsbInterfaceDescriptor)) {
continue;
}
UsbInterfaceDescriptor iface = (UsbInterfaceDescriptor) descriptor;
- shouldIgnoreDevice = isBlackListed(iface.getUsbClass(), iface.getUsbSubclass());
+ shouldIgnoreDevice = isDenyListed(iface.getUsbClass(), iface.getUsbSubclass());
if (!shouldIgnoreDevice) {
break;
}
}
if (shouldIgnoreDevice) {
if (DEBUG) {
- Slog.d(TAG, "usb interface class is black listed");
+ Slog.d(TAG, "usb interface class is deny listed");
}
return false;
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 1025bf5..ec7d4bd 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -922,7 +922,7 @@
contaminantDetectionStatus);
mPorts.put(portId, portInfo);
} else {
- // Sanity check that ports aren't changing definition out from under us.
+ // Validate that ports aren't changing definition out from under us.
if (supportedModes != portInfo.mUsbPort.getSupportedModes()) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from "
+ "USB port driver (should be immutable): "
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 6c13cd7..ee564a9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -221,14 +221,6 @@
}
}
- @Override
- public void onStartUser(int userHandle) {
- }
-
- @Override
- public void onSwitchUser(int userHandle) {
- }
-
private synchronized void initSoundTriggerHelper() {
if (mSoundTriggerHelper == null) {
mSoundTriggerHelper = new SoundTriggerHelper(mContext);
@@ -697,7 +689,7 @@
synchronized (mLock) {
ModuleProperties properties = mSoundTriggerHelper.getModuleProperties();
sEventLogger.log(new SoundTriggerLogger.StringEvent(
- "getModuleProperties(): " + properties.toString()));
+ "getModuleProperties(): " + properties));
return properties;
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 9621f68..0f898f8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -189,10 +189,10 @@
}
@Override
- public void onSwitchUser(@NonNull UserInfo from, @NonNull UserInfo to) {
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
if (DEBUG_USER) Slog.d(TAG, "onSwitchUser(" + from + " > " + to + ")");
- mServiceStub.switchUser(to.id);
+ mServiceStub.switchUser(to.getUserIdentifier());
}
class LocalService extends VoiceInteractionManagerInternal {
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index d585666..c9903f9 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -23,6 +23,14 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "CtsTelecomTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3365ab7..0469fa5 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -462,15 +462,15 @@
/**
* Call supports adding participants to the call via
- * {@link #addConferenceParticipants(List)}.
- * @hide
+ * {@link #addConferenceParticipants(List)}. Once participants are added, the call becomes
+ * an adhoc conference call ({@link #PROPERTY_IS_ADHOC_CONFERENCE}).
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
/**
* When set for a call, indicates that this {@code Call} can be transferred to another
* number.
- * Call supports the blind and assured call transfer feature.
+ * Call supports the confirmed and unconfirmed call transfer feature.
*
* @hide
*/
@@ -599,8 +599,11 @@
/**
* Indicates that the call is an adhoc conference call. This property can be set for both
- * incoming and outgoing calls.
- * @hide
+ * incoming and outgoing calls. An adhoc conference call is formed using
+ * {@link #addConferenceParticipants(List)},
+ * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}, or
+ * {@link TelecomManager#startConference(List, Bundle)}, rather than by merging existing
+ * call using {@link #conference(Call)}.
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000;
@@ -1593,8 +1596,8 @@
* Instructs this {@code Call} to be transferred to another number.
*
* @param targetNumber The address to which the call will be transferred.
- * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
- * if {@code false}, it will initiate BLIND transfer.
+ * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
+ * if {@code false}, it will initiate an unconfirmed transfer.
*
* @hide
*/
@@ -1775,7 +1778,6 @@
* See {@link Details#CAPABILITY_ADD_PARTICIPANT}.
*
* @param participants participants to be pulled to existing call.
- * @hide
*/
public void addConferenceParticipants(@NonNull List<Uri> participants) {
mInCallAdapter.addConferenceParticipants(mTelecomCallId, participants);
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index d960552..39c3ff9 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -181,8 +181,8 @@
/**
* Returns whether this conference is requesting that the system play a ringback tone
- * on its behalf.
- * @hide
+ * on its behalf. A ringback tone may be played when an outgoing conference is in the process of
+ * connecting to give the user an audible indication of that process.
*/
public final boolean isRingbackRequested() {
return mRingbackRequested;
@@ -329,7 +329,6 @@
/**
* Notifies the {@link Conference} of a request to add a new participants to the conference call
* @param participants that will be added to this conference call
- * @hide
*/
public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
@@ -340,7 +339,6 @@
* the default dialer's {@link InCallService}.
*
* @param videoState The video state in which to answer the connection.
- * @hide
*/
public void onAnswer(int videoState) {}
@@ -360,7 +358,6 @@
* a request to reject.
* For managed {@link ConnectionService}s, this will be called when the user rejects a call via
* the default dialer's {@link InCallService}.
- * @hide
*/
public void onReject() {}
@@ -380,7 +377,6 @@
/**
* Sets state to be ringing.
- * @hide
*/
public final void setRinging() {
setState(Connection.STATE_RINGING);
@@ -506,7 +502,6 @@
* that do not play a ringback tone themselves in the conference's audio stream.
*
* @param ringback Whether the ringback tone is to be played.
- * @hide
*/
public final void setRingbackRequested(boolean ringback) {
if (mRingbackRequested != ringback) {
@@ -773,7 +768,6 @@
*
* @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
* @return A {@code Conference} which indicates failure.
- * @hide
*/
public @NonNull static Conference createFailedConference(
@NonNull DisconnectCause disconnectCause, @NonNull PhoneAccountHandle phoneAccount) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa99095..00b7116 100755
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -383,15 +383,17 @@
/**
* When set, indicates that this {@link Connection} supports initiation of a conference call
- * by directly adding participants using {@link #onAddConferenceParticipants(List)}.
- * @hide
+ * by directly adding participants using {@link #onAddConferenceParticipants(List)}. When
+ * participants are added to a {@link Connection}, it will be replaced by a {@link Conference}
+ * instance with {@link #PROPERTY_IS_ADHOC_CONFERENCE} set to indicate that it is an adhoc
+ * conference call.
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
/**
* Indicates that this {@code Connection} can be transferred to another
* number.
- * Connection supports the blind and assured call transfer feature.
+ * Connection supports the confirmed and unconfirmed call transfer feature.
* @hide
*/
public static final int CAPABILITY_TRANSFER = 0x08000000;
@@ -526,10 +528,9 @@
public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
/**
- * Set by the framework to indicate that it is an adhoc conference call.
+ * Set by the framework to indicate that a call is an adhoc conference call.
* <p>
- * This is used for Outgoing and incoming conference calls.
- * @hide
+ * This is used for outgoing and incoming conference calls.
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 1 << 12;
@@ -3034,7 +3035,6 @@
* Supports initiation of a conference call by directly adding participants to an ongoing call.
*
* @param participants with which conference call will be formed.
- * @hide
*/
public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 56cba1d..3646647 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1880,6 +1880,7 @@
mConferenceById.put(callId, conference);
mIdByConference.put(conference, callId);
+
conference.addListener(mConferenceListener);
ParcelableConference parcelableConference = new ParcelableConference.Builder(
request.getAccountHandle(), conference.getState())
@@ -2678,15 +2679,15 @@
return null;
}
/**
- * Create a {@code Connection} given an incoming request. This is used to attach to existing
- * incoming conference call.
+ * Create a {@code Conference} given an incoming request. This is used to attach to an incoming
+ * conference call initiated via
+ * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}.
*
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
- * @param request Details about the incoming call.
- * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * @param request Details about the incoming conference call.
+ * @return The {@code Conference} object to satisfy this call, or {@code null} to
* not handle the call.
- * @hide
*/
public @Nullable Conference onCreateIncomingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2771,7 +2772,6 @@
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
- * @hide
*/
public void onCreateIncomingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2792,7 +2792,6 @@
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
- * @hide
*/
public void onCreateOutgoingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2841,7 +2840,8 @@
/**
* Create a {@code Conference} given an outgoing request. This is used to initiate new
- * outgoing conference call.
+ * outgoing conference call requested via
+ * {@link TelecomManager#startConference(List, Bundle)}.
*
* @param connectionManagerPhoneAccount The connection manager account to use for managing
* this call.
@@ -2861,7 +2861,6 @@
* @param request Details about the outgoing call.
* @return The {@code Conference} object to satisfy this call, or the result of an invocation
* of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
- * @hide
*/
public @Nullable Conference onCreateOutgoingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index dd6c153..ab35aff 100755
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -107,8 +107,8 @@
*
* @param callId The identifier of the call to transfer.
* @param targetNumber The address to transfer to.
- * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
- * if {@code false}, it will initiate BLIND transfer.
+ * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
+ * if {@code false}, it will initiate unconfirmed transfer.
*/
public void transferCall(@NonNull String callId, @NonNull Uri targetNumber,
boolean isConfirmationRequired) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8eebbed..bcb1736 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1867,11 +1867,13 @@
/**
* Registers a new incoming conference. A {@link ConnectionService} should invoke this method
- * when it has an incoming conference. For managed {@link ConnectionService}s, the specified
- * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
- * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
- * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
- * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
+ * when it has an incoming conference. An incoming {@link Conference} is an adhoc conference
+ * call initiated on another device which the user is being invited to join in. For managed
+ * {@link ConnectionService}s, the specified {@link PhoneAccountHandle} must have been
+ * registered with {@link #registerPhoneAccount} and the user must have enabled the
+ * corresponding {@link PhoneAccount}. This can be checked using
+ * {@link #getPhoneAccount(PhoneAccountHandle)}. Self-managed {@link ConnectionService}s must
+ * have {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
* <p>
* The incoming conference you are adding is assumed to have a video state of
* {@link VideoProfile#STATE_AUDIO_ONLY}, unless the extra value
@@ -1879,8 +1881,9 @@
* <p>
* Once invoked, this method will cause the system to bind to the {@link ConnectionService}
* associated with the {@link PhoneAccountHandle} and request additional information about the
- * call (See {@link ConnectionService#onCreateIncomingConference}) before starting the incoming
- * call UI.
+ * call (See
+ * {@link ConnectionService#onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)})
+ * before starting the incoming call UI.
* <p>
* For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
* the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or
@@ -1890,7 +1893,6 @@
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
* {@link ConnectionService#onCreateIncomingConference}.
- * @hide
*/
public void addNewIncomingConference(@NonNull PhoneAccountHandle phoneAccount,
@NonNull Bundle extras) {
@@ -2111,8 +2113,8 @@
/**
- * Place a new conference call with the provided participants using the system telecom service
- * This method doesn't support placing of emergency calls.
+ * Place a new adhoc conference call with the provided participants using the system telecom
+ * service. This method doesn't support placing of emergency calls.
*
* An adhoc conference call is established by providing a list of addresses to
* {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
@@ -2130,7 +2132,6 @@
*
* @param participants List of participants to start conference with
* @param extras Bundle of extras to use with the call
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void startConference(@NonNull List<Uri> participants,
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index dee5a98..7c6f1df 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -326,6 +326,8 @@
*/
void handleCallIntent(in Intent intent, in String callingPackageProxy);
+ void cleanupStuckCalls();
+
void setTestDefaultCallRedirectionApp(String packageName);
void setTestPhoneAcctSuggestionComponent(String flattenedComponentName);
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 48794cb..502bfa3 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -47,7 +47,7 @@
ALLOWED,
/**
* Indicates that the denial is due to a transient device state
- * (e.g. app-ops, location master switch)
+ * (e.g. app-ops, location main switch)
*/
DENIED_SOFT,
/**
@@ -316,7 +316,7 @@
return LocationPermissionResult.ALLOWED;
}
- // Check the system-wide requirements. If the location master switch is off or
+ // Check the system-wide requirements. If the location main switch is off or
// the app's profile isn't in foreground, return a soft denial.
if (!checkSystemLocationAccess(context, query.callingUid, query.callingPid)) {
return LocationPermissionResult.DENIED_SOFT;
@@ -340,7 +340,7 @@
}
// At this point, we're out of location checks to do. If the app bypassed all the previous
- // ones due to the SDK grandfathering schemes, allow it access.
+ // ones due to the SDK backwards compatibility schemes, allow it access.
return LocationPermissionResult.ALLOWED;
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 71a1964..0c46394 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -74,7 +74,8 @@
* <li>return false: if the caller lacks all of these permissions and doesn't support runtime
* permissions. This implies that the user revoked the ability to read phone state
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
+ * so we return false to indicate that the calling function should return placeholder
+ * data.
* </ul>
*
* <p>Note: for simplicity, this method always returns false for callers using legacy
@@ -119,7 +120,8 @@
* <li>return false: if the caller lacks all of these permissions and doesn't support runtime
* permissions. This implies that the user revoked the ability to read phone state
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
+ * so we return false to indicate that the calling function should return placeholder
+ * data.
* </ul>
*
* <p>Note: for simplicity, this method always returns false for callers using legacy
@@ -225,7 +227,7 @@
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
@@ -249,7 +251,7 @@
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission or carrier privileges. In this case the caller would expect to have access
* to the device identifiers so false is returned instead of throwing a SecurityException
- * to indicate the calling function should return dummy data.
+ * to indicate the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
@@ -271,7 +273,7 @@
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
@@ -295,7 +297,7 @@
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
index 5e1f556..7af0d1b 100644
--- a/telephony/common/com/google/android/mms/pdu/PduComposer.java
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -1051,7 +1051,7 @@
}
if (dataLength != (attachment.getLength() - headerLength)) {
- throw new RuntimeException("BUG: Length sanity check failed");
+ throw new RuntimeException("BUG: Length correctness check failed");
}
mStack.pop();
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index fcd5b8f..b61ad36 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -72,7 +72,7 @@
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = false;
- private static final long DUMMY_THREAD_ID = Long.MAX_VALUE;
+ private static final long PLACEHOLDER_THREAD_ID = Long.MAX_VALUE;
/**
* The uri of temporary drm objects.
@@ -1340,7 +1340,7 @@
// Save parts first to avoid inconsistent message is loaded
// while saving the parts.
- long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
+ long placeholderId = System.currentTimeMillis(); // Placeholder ID of the msg.
// Figure out if this PDU is a text-only message
boolean textOnly = true;
@@ -1364,7 +1364,7 @@
for (int i = 0; i < partsNum; i++) {
PduPart part = body.getPart(i);
messageSize += part.getDataLength();
- persistPart(part, dummyId, preOpenedFiles);
+ persistPart(part, placeholderId, preOpenedFiles);
// If we've got anything besides text/plain or SMIL part, then we've got
// an mms message with some other type of attachment.
@@ -1395,14 +1395,14 @@
throw new MmsException("persist() failed: return null.");
}
// Get the real ID of the PDU and update all parts which were
- // saved with the dummy ID.
+ // saved with the placeholder ID.
msgId = ContentUris.parseId(res);
}
values = new ContentValues(1);
values.put(Part.MSG_ID, msgId);
SqliteWrapper.update(mContext, mContentResolver,
- Uri.parse("content://mms/" + dummyId + "/part"),
+ Uri.parse("content://mms/" + placeholderId + "/part"),
values, null, null);
// We should return the longest URI of the persisted PDU, for
// example, if input URI is "content://mms/inbox" and the _ID of
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5ea4c7b..fa229fb 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -772,7 +772,7 @@
* {@link #KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL}). If false, this device will fallback to
* circuit switch for supplementary services and will disable this capability for IMS entirely.
*
- * The default value for this key is {@code true}.
+ * The default value for this key is {@code false}.
*/
public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL =
"carrier_supports_ss_over_ut_bool";
@@ -1165,15 +1165,14 @@
/**
* Determines whether adhoc conference calls are supported by a carrier. When {@code true},
* adhoc conference calling is supported, {@code false otherwise}.
- * @hide
*/
public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL =
"support_adhoc_conference_calls_bool";
/**
- * Determines whether conference participants can be added to existing call. When {@code true},
+ * Determines whether conference participants can be added to existing call to form an adhoc
+ * conference call (in contrast to merging calls to form a conference). When {@code true},
* adding conference participants to existing call is supported, {@code false otherwise}.
- * @hide
*/
public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL =
"support_add_conference_participants_bool";
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index aa12301..cdf7351 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -33,10 +33,12 @@
public abstract class CellLocation {
/**
- * This method will not do anything.
+ * Request an updated CellLocation for callers targeting SDK 30 or older.
*
- * Whenever location changes, a callback will automatically be be sent to
- * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}.
+ * Whenever Android is aware of location changes, a callback will automatically be sent to
+ * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}. This API requests an
+ * additional location update for cases where power saving might cause location updates to be
+ * missed.
*
* <p>This method is a no-op for callers targeting SDK level 31 or greater.
* <p>This method is a no-op for callers that target SDK level 29 or 30 and lack
@@ -44,14 +46,7 @@
* <p>This method is a no-op for callers that target SDK level 28 or below and lack
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
*
- * Callers wishing to request a single location update should use
- * {@link TelephonyManager#requestCellInfoUpdate}.
- *
- * @deprecated this method has undesirable side-effects, and it calls into the OS without
- * access to a {@link android.content.Context Context}, meaning that certain safety checks and
- * attribution are error-prone. Given that this method has numerous downsides, and given that
- * there are long-available superior alternatives, callers are strongly discouraged from using
- * this method.
+ * @deprecated use {@link TelephonyManager#requestCellInfoUpdate}.
*/
@Deprecated
public static void requestLocationUpdate() {
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 8e50bba..766019e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -149,7 +149,7 @@
mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
- mSsRsrq = inRangeOrUnavailable(ssRsrq, -20, -3);
+ mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
updateLevel(null, null);
}
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index 3f671ca..18d6f46 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -509,7 +509,7 @@
* provided directory is the same as what has been previously configured.
*
* The {@link File} supplied as a root temp file directory must already exist. If not, an
- * {@link IllegalArgumentException} will be thrown. In addition, as an additional sanity
+ * {@link IllegalArgumentException} will be thrown. In addition, as an additional correctness
* check, an {@link IllegalArgumentException} will be thrown if you attempt to set the temp
* file root directory to one of your data roots (the value of {@link Context#getDataDir()},
* {@link Context#getFilesDir()}, or {@link Context#getCacheDir()}).
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 3dbbf41..aee8617 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -56,8 +56,6 @@
private final @DataState int mState;
private final @NetworkType int mNetworkType;
private final @DataFailureCause int mFailCause;
- private final @ApnType int mApnTypes;
- private final String mApn;
private final LinkProperties mLinkProperties;
private final ApnSetting mApnSetting;
@@ -76,7 +74,10 @@
@ApnType int apnTypes, @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause) {
- this(state, networkType, apnTypes, apn, linkProperties, failCause, null);
+ this(state, networkType, linkProperties, failCause, new ApnSetting.Builder()
+ .setApnTypeBitmask(apnTypes)
+ .setApnName(apn)
+ .build());
}
@@ -85,26 +86,19 @@
*
* @param state The state of the data connection
* @param networkType The access network that is/would carry this data connection
- * @param apnTypes The APN types that this data connection carries
- * @param apn The APN of this data connection
* @param linkProperties If the data connection is connected, the properties of the connection
* @param failCause In case a procedure related to this data connection fails, a non-zero error
* code indicating the cause of the failure.
* @param apnSetting If there is a valid APN for this Data Connection, then the APN Settings;
* if there is no valid APN setting for the specific type, then this will be null
- * @hide
*/
private PreciseDataConnectionState(@DataState int state,
@NetworkType int networkType,
- @ApnType int apnTypes,
- @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause,
@Nullable ApnSetting apnSetting) {
mState = state;
mNetworkType = networkType;
- mApnTypes = apnTypes;
- mApn = apn;
mLinkProperties = linkProperties;
mFailCause = failCause;
mApnSetting = apnSetting;
@@ -118,11 +112,9 @@
private PreciseDataConnectionState(Parcel in) {
mState = in.readInt();
mNetworkType = in.readInt();
- mApnTypes = in.readInt();
- mApn = in.readString();
- mLinkProperties = (LinkProperties) in.readParcelable(null);
+ mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader());
mFailCause = in.readInt();
- mApnSetting = (ApnSetting) in.readParcelable(null);
+ mApnSetting = in.readParcelable(ApnSetting.class.getClassLoader());
}
/**
@@ -181,7 +173,7 @@
@Deprecated
@SystemApi
public @ApnType int getDataConnectionApnTypeBitMask() {
- return mApnTypes;
+ return (mApnSetting != null) ? mApnSetting.getApnTypeBitmask() : ApnSetting.TYPE_NONE;
}
/**
@@ -194,7 +186,7 @@
@SystemApi
@Deprecated
public String getDataConnectionApn() {
- return mApn;
+ return (mApnSetting != null) ? mApnSetting.getApnName() : "";
}
/**
@@ -245,8 +237,6 @@
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mState);
out.writeInt(mNetworkType);
- out.writeInt(mApnTypes);
- out.writeString(mApn);
out.writeParcelable(mLinkProperties, flags);
out.writeInt(mFailCause);
out.writeParcelable(mApnSetting, flags);
@@ -266,8 +256,7 @@
@Override
public int hashCode() {
- return Objects.hash(mState, mNetworkType, mFailCause, mApnTypes, mApn, mLinkProperties,
- mApnSetting);
+ return Objects.hash(mState, mNetworkType, mFailCause, mLinkProperties, mApnSetting);
}
@@ -279,8 +268,6 @@
return mState == that.mState
&& mNetworkType == that.mNetworkType
&& mFailCause == that.mFailCause
- && mApnTypes == that.mApnTypes
- && Objects.equals(mApn, that.mApn)
&& Objects.equals(mLinkProperties, that.mLinkProperties)
&& Objects.equals(mApnSetting, that.mApnSetting);
}
@@ -292,8 +279,9 @@
sb.append("Data Connection state: " + mState);
sb.append(", Network type: " + mNetworkType);
- sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(mApnTypes));
- sb.append(", APN: " + mApn);
+ sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(
+ getDataConnectionApnTypeBitMask()));
+ sb.append(", APN: " + getDataConnectionApn());
sb.append(", Link properties: " + mLinkProperties);
sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
sb.append(", Apn Setting: " + mApnSetting);
@@ -313,12 +301,6 @@
/** The network type associated with this data connection */
private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- /** The APN types that this data connection carries */
- private @ApnType int mApnTypes = ApnSetting.TYPE_NONE;
-
- /** The APN of this data connection */
- private @NonNull String mApn = "";
-
/** If the data connection is connected, the properties of the connection */
private @Nullable LinkProperties mLinkProperties = null;
@@ -354,28 +336,6 @@
}
/**
- * Set the APN types that this data connection carries
- *
- * @param apnTypes The APN types
- * @return The builder
- */
- public Builder setApnTypes(@ApnType int apnTypes) {
- mApnTypes = apnTypes;
- return this;
- }
-
- /**
- * Set the APN of this data connection
- *
- * @param apn The APN of this data connection
- * @return The builder
- */
- public Builder setApn(@NonNull String apn) {
- mApn = apn;
- return this;
- }
-
- /**
* Set the link properties of the connection.
*
* @param linkProperties Link properties
@@ -415,8 +375,8 @@
* @return The {@link PreciseDataConnectionState} instance
*/
public PreciseDataConnectionState build() {
- return new PreciseDataConnectionState(mState, mNetworkType, mApnTypes, mApn,
- mLinkProperties, mFailCause, mApnSetting);
+ return new PreciseDataConnectionState(mState, mNetworkType, mLinkProperties, mFailCause,
+ mApnSetting);
}
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 183fdcc..2b26087 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -39,7 +39,9 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.ITelephony;
@@ -74,11 +76,16 @@
public final class SmsManager {
private static final String TAG = "SmsManager";
- /** Singleton object constructed during class initialization. */
- private static final SmsManager sInstance = new SmsManager(
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
private static final Object sLockObject = new Object();
+ @GuardedBy("sLockObject")
+ private static final Map<Pair<Context, Integer>, SmsManager> sSubInstances =
+ new ArrayMap<>();
+
+ /** Singleton object constructed during class initialization. */
+ private static final SmsManager DEFAULT_INSTANCE = getSmsManagerForContextAndSubscriptionId(
+ null, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+
/** SMS record length from TS 51.011 10.5.3
* @hide
*/
@@ -89,13 +96,16 @@
*/
public static final int CDMA_SMS_RECORD_LENGTH = 255;
- private static final Map<Integer, SmsManager> sSubInstances =
- new ArrayMap<Integer, SmsManager>();
-
/** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mSubId;
+ /**
+ * Context this SmsManager is for. Can be {@code null} in the case the manager was created via
+ * legacy APIs
+ */
+ private final @Nullable Context mContext;
+
/*
* Key for the various carrier-dependent configuration values.
* Some of the values are used by the system in processing SMS or MMS messages. Others
@@ -325,6 +335,34 @@
}
/**
+ * Get {@link Context#getOpPackageName()} if this manager has a context, otherwise a dummy
+ * value.
+ *
+ * @return The package name to be used for app-ops checks
+ */
+ private @Nullable String getOpPackageName() {
+ if (mContext == null) {
+ return null;
+ } else {
+ return mContext.getOpPackageName();
+ }
+ }
+
+ /**
+ * Get {@link Context#getAttributionTag()} ()} if this manager has a context, otherwise get the
+ * default attribution tag.
+ *
+ * @return The attribution tag to be used for app-ops checks
+ */
+ private @Nullable String getAttributionTag() {
+ if (mContext == null) {
+ return null;
+ } else {
+ return mContext.getAttributionTag();
+ }
+ }
+
+ /**
* Send a text based SMS.
*
* <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -424,7 +462,8 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, null, null, 0L /* messageId */);
+ true /* persistMessage*/, getOpPackageName(), getAttributionTag(),
+ 0L /* messageId */);
}
@@ -443,7 +482,8 @@
@Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveryIntent,
long messageId) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, null, null, messageId);
+ true /* persistMessage*/, getOpPackageName(), getAttributionTag(),
+ messageId);
}
/**
@@ -653,8 +693,8 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */, null, null,
- 0L /* messageId */);
+ false /* persistMessage */, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
private void sendTextMessageInternal(
@@ -939,8 +979,8 @@
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, null, null,
- 0L /* messageId */);
+ deliveryIntents, true /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
/**
@@ -957,8 +997,8 @@
@NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
@Nullable List<PendingIntent> deliveryIntents, long messageId) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, null, null,
- messageId);
+ deliveryIntents, true /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), messageId);
}
/**
@@ -1088,8 +1128,8 @@
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/, null, null,
- 0L /* messageId */);
+ deliveryIntents, false /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
/**
@@ -1451,9 +1491,57 @@
* @return the {@link SmsManager} associated with the default subscription id.
*
* @see SubscriptionManager#getDefaultSmsSubscriptionId()
+ *
+ * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)}
+ * instead
*/
+ @Deprecated
public static SmsManager getDefault() {
- return sInstance;
+ return DEFAULT_INSTANCE;
+ }
+
+ /**
+ * Get the instance of the SmsManager associated with a particular context and subscription ID.
+ *
+ * @param context The context the manager belongs to
+ * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager}
+ *
+ * @return the instance of the SmsManager associated with subscription
+ *
+ * @hide
+ */
+ public static @NonNull SmsManager getSmsManagerForContextAndSubscriptionId(
+ @Nullable Context context, int subId) {
+ synchronized(sLockObject) {
+ Pair<Context, Integer> key = new Pair<>(context, subId);
+
+ SmsManager smsManager = sSubInstances.get(key);
+ if (smsManager == null) {
+ smsManager = new SmsManager(context, subId);
+ sSubInstances.put(key, smsManager);
+ }
+ return smsManager;
+ }
+ }
+
+ /**
+ * Get the instance of the SmsManager associated with a particular subscription ID.
+ *
+ * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will
+ * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}.
+ * </p>
+ *
+ * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager}
+ * @return the instance of the SmsManager associated with subscription
+ *
+ * @see SubscriptionManager#getActiveSubscriptionInfoList()
+ * @see SubscriptionManager#getDefaultSmsSubscriptionId()
+ * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)}
+ * .{@link #createForSubscriptionId createForSubscriptionId(subId)} instead
+ */
+ @Deprecated
+ public static SmsManager getSmsManagerForSubscriptionId(int subId) {
+ return getSmsManagerForContextAndSubscriptionId(null, subId);
}
/**
@@ -1469,18 +1557,12 @@
* @see SubscriptionManager#getActiveSubscriptionInfoList()
* @see SubscriptionManager#getDefaultSmsSubscriptionId()
*/
- public static SmsManager getSmsManagerForSubscriptionId(int subId) {
- synchronized(sLockObject) {
- SmsManager smsManager = sSubInstances.get(subId);
- if (smsManager == null) {
- smsManager = new SmsManager(subId);
- sSubInstances.put(subId, smsManager);
- }
- return smsManager;
- }
+ public @NonNull SmsManager createForSubscriptionId(int subId) {
+ return getSmsManagerForContextAndSubscriptionId(mContext, subId);
}
- private SmsManager(int subId) {
+ private SmsManager(@Nullable Context context, int subId) {
+ mContext = context;
mSubId = subId;
}
@@ -1715,8 +1797,7 @@
* operation is performed on the correct subscription.
* </p>
*
- * @param messageIndex This is the same index used to access a message
- * from {@link #getMessagesFromIcc()}.
+ * @param messageIndex the message index of the message in the ICC (1-based index).
* @return true for success, false if the operation fails. Failure can be due to IPC failure,
* RIL/modem error which results in SMS failed to be deleted on SIM
*
@@ -1798,7 +1879,7 @@
* operation is performed on the correct subscription.
* </p>
*
- * @return <code>List</code> of <code>SmsMessage</code> objects
+ * @return <code>List</code> of <code>SmsMessage</code> objects for valid records only.
*
* {@hide}
*/
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4ad52ae..a71a965 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -94,10 +94,9 @@
/** An invalid subscription identifier */
public static final int INVALID_SUBSCRIPTION_ID = -1;
- /** Base value for Dummy SUBSCRIPTION_ID's. */
- /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
- /** @hide */
- public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
+ /** Base value for placeholder SUBSCRIPTION_ID's. */
+ /** @hide */
+ public static final int PLACEHOLDER_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
/** An invalid phone identifier */
/** @hide */
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
index c9540fb..8308821 100644
--- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -92,6 +92,12 @@
ImsManager.class,
context -> new ImsManager(context)
);
+ SystemServiceRegistry.registerContextAwareService(
+ Context.SMS_SERVICE,
+ SmsManager.class,
+ context -> SmsManager.getSmsManagerForContextAndSubscriptionId(context,
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
+ );
}
/** @hide */
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index e8f3f1e..eadb726 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -92,8 +92,8 @@
}
/**
- * Sets the originating number whitelist for the visual voicemail SMS filter. If the list is
- * not null only the SMS messages from a number in the list can be considered as a visual
+ * Sets the originating number allow list for the visual voicemail SMS filter. If the list
+ * is not null only the SMS messages from a number in the list can be considered as a visual
* voicemail SMS. Otherwise, messages from any address will be considered.
*/
public Builder setOriginatingNumbers(List<String> originatingNumbers) {
@@ -133,7 +133,7 @@
public final String clientPrefix;
/**
- * The originating number whitelist for the visual voicemail SMS filter of a phone account. If
+ * The originating number allow list for the visual voicemail SMS filter of a phone account. If
* the list is not null only the SMS messages from a number in the list can be considered as a
* visual voicemail SMS. Otherwise, messages from any address will be considered.
*/
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index bfb54b0..e60ae89 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1643,7 +1643,7 @@
*
* <pre><code>
* // Create an MMS proxy address with a hostname. A network might not be
- * // available, so supply a dummy (0.0.0.0) IPv4 address to avoid DNS lookup.
+ * // available, so supply a placeholder (0.0.0.0) IPv4 address to avoid DNS lookup.
* String host = "mms.example.com";
* byte[] ipAddress = new byte[4];
* InetAddress mmsProxy;
@@ -1828,7 +1828,8 @@
* {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
* resolution. To avoid this requirement when setting a hostname, call
* {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
- * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+ * hostname and a placeholder IP address. See {@link ApnSetting.Builder above} for an
+ * example.
*
* @param proxy the proxy address to set for the APN
* @deprecated use {@link #setProxyAddress(String)} instead.
@@ -1882,7 +1883,8 @@
* {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
* resolution. To avoid this requirement when setting a hostname, call
* {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
- * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+ * hostname and a placeholder IP address. See {@link ApnSetting.Builder above} for an
+ * example.
*
* @param mmsProxy the MMS proxy address to set for the APN
* @deprecated use {@link #setMmsProxyAddress(String)} instead.
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 80c38cb..8857b9b 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -815,7 +815,7 @@
* Transfers an ongoing call.
*
* @param number number to be transferred to.
- * @param isConfirmationRequired indicates blind or assured transfer.
+ * @param isConfirmationRequired indicates whether confirmation of the transfer is required.
*/
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
if (mClosed) {
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 0d6b31d..30389a290 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -27,7 +27,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
+import java.util.HashMap;
+import java.util.Map;
/**
* Provides details on why an IMS call failed. Applications can use the methods in this class to
* get local or network fault behind an IMS services failure. For example, if the code is
@@ -1095,6 +1096,196 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ImsCode {}
+
+ private static final Map<Integer, String> sImsCodeMap;
+ static {
+ sImsCodeMap = new HashMap<>();
+ sImsCodeMap.put(CODE_UNSPECIFIED, "CODE_UNSPECIFIED");
+ sImsCodeMap.put(CODE_LOCAL_ILLEGAL_ARGUMENT, "CODE_LOCAL_ILLEGAL_ARGUMENT");
+ sImsCodeMap.put(CODE_LOCAL_ILLEGAL_STATE, "CODE_LOCAL_ILLEGAL_STATE");
+ sImsCodeMap.put(CODE_LOCAL_INTERNAL_ERROR, "CODE_LOCAL_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_LOCAL_IMS_SERVICE_DOWN, "CODE_LOCAL_IMS_SERVICE_DOWN");
+ sImsCodeMap.put(CODE_LOCAL_NO_PENDING_CALL, "CODE_LOCAL_NO_PENDING_CALL");
+ sImsCodeMap.put(CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+ "CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE");
+ sImsCodeMap.put(CODE_LOCAL_POWER_OFF, "CODE_LOCAL_POWER_OFF");
+ sImsCodeMap.put(CODE_LOCAL_LOW_BATTERY, "CODE_LOCAL_LOW_BATTERY");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_NO_SERVICE, "CODE_LOCAL_NETWORK_NO_SERVICE");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, "CODE_LOCAL_NETWORK_NO_LTE_COVERAGE");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_ROAMING, "CODE_LOCAL_NETWORK_ROAMING");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_IP_CHANGED, "CODE_LOCAL_NETWORK_IP_CHANGED");
+ sImsCodeMap.put(CODE_LOCAL_SERVICE_UNAVAILABLE, "CODE_LOCAL_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_LOCAL_NOT_REGISTERED, "CODE_LOCAL_NOT_REGISTERED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_EXCEEDED, "CODE_LOCAL_CALL_EXCEEDED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_BUSY, "CODE_LOCAL_CALL_BUSY");
+ sImsCodeMap.put(CODE_LOCAL_CALL_DECLINE, "CODE_LOCAL_CALL_DECLINE");
+ sImsCodeMap.put(CODE_LOCAL_CALL_VCC_ON_PROGRESSING, "CODE_LOCAL_CALL_VCC_ON_PROGRESSING");
+ sImsCodeMap.put(CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
+ "CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_CS_RETRY_REQUIRED, "CODE_LOCAL_CALL_CS_RETRY_REQUIRED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
+ "CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_TERMINATED, "CODE_LOCAL_CALL_TERMINATED");
+ sImsCodeMap.put(CODE_LOCAL_HO_NOT_FEASIBLE, "CODE_LOCAL_HO_NOT_FEASIBLE");
+ sImsCodeMap.put(CODE_TIMEOUT_1XX_WAITING, "CODE_TIMEOUT_1XX_WAITING");
+ sImsCodeMap.put(CODE_TIMEOUT_NO_ANSWER, "CODE_TIMEOUT_NO_ANSWER");
+ sImsCodeMap.put(CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE, "CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE");
+ sImsCodeMap.put(CODE_CALL_BARRED, "CODE_CALL_BARRED");
+ sImsCodeMap.put(CODE_FDN_BLOCKED, "CODE_FDN_BLOCKED");
+ sImsCodeMap.put(CODE_IMEI_NOT_ACCEPTED, "CODE_IMEI_NOT_ACCEPTED");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_USSD, "CODE_DIAL_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_SS, "CODE_DIAL_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_DIAL, "CODE_DIAL_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_DIAL_VIDEO, "CODE_DIAL_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_DIAL, "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO,
+ "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_SS, "CODE_DIAL_VIDEO_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_USSD, "CODE_DIAL_VIDEO_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_SIP_REDIRECTED, "CODE_SIP_REDIRECTED");
+ sImsCodeMap.put(CODE_SIP_BAD_REQUEST, "CODE_SIP_BAD_REQUEST");
+ sImsCodeMap.put(CODE_SIP_FORBIDDEN, "CODE_SIP_FORBIDDEN");
+ sImsCodeMap.put(CODE_SIP_NOT_FOUND, "CODE_SIP_NOT_FOUND");
+ sImsCodeMap.put(CODE_SIP_NOT_SUPPORTED, "CODE_SIP_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_SIP_REQUEST_TIMEOUT, "CODE_SIP_REQUEST_TIMEOUT");
+ sImsCodeMap.put(CODE_SIP_TEMPRARILY_UNAVAILABLE, "CODE_SIP_TEMPRARILY_UNAVAILABLE");
+ sImsCodeMap.put(CODE_SIP_BAD_ADDRESS, "CODE_SIP_BAD_ADDRESS");
+ sImsCodeMap.put(CODE_SIP_BUSY, "CODE_SIP_BUSY");
+ sImsCodeMap.put(CODE_SIP_REQUEST_CANCELLED, "CODE_SIP_REQUEST_CANCELLED");
+ sImsCodeMap.put(CODE_SIP_NOT_ACCEPTABLE, "CODE_SIP_NOT_ACCEPTABLE");
+ sImsCodeMap.put(CODE_SIP_NOT_REACHABLE, "CODE_SIP_NOT_REACHABLE");
+ sImsCodeMap.put(CODE_SIP_CLIENT_ERROR, "CODE_SIP_CLIENT_ERROR");
+ sImsCodeMap.put(CODE_SIP_TRANSACTION_DOES_NOT_EXIST, "CODE_SIP_TRANSACTION_DOES_NOT_EXIST");
+ sImsCodeMap.put(CODE_SIP_SERVER_INTERNAL_ERROR, "CODE_SIP_SERVER_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_SIP_SERVICE_UNAVAILABLE, "CODE_SIP_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_SIP_SERVER_TIMEOUT, "CODE_SIP_SERVER_TIMEOUT");
+ sImsCodeMap.put(CODE_SIP_SERVER_ERROR, "CODE_SIP_SERVER_ERROR");
+ sImsCodeMap.put(CODE_SIP_USER_REJECTED, "CODE_SIP_USER_REJECTED");
+ sImsCodeMap.put(CODE_SIP_GLOBAL_ERROR, "CODE_SIP_GLOBAL_ERROR");
+ sImsCodeMap.put(CODE_EMERGENCY_TEMP_FAILURE, "CODE_EMERGENCY_TEMP_FAILURE");
+ sImsCodeMap.put(CODE_EMERGENCY_PERM_FAILURE, "CODE_EMERGENCY_PERM_FAILURE");
+ sImsCodeMap.put(CODE_SIP_USER_MARKED_UNWANTED, "CODE_SIP_USER_MARKED_UNWANTED");
+ sImsCodeMap.put(CODE_SIP_METHOD_NOT_ALLOWED, "CODE_SIP_METHOD_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_SIP_PROXY_AUTHENTICATION_REQUIRED,
+ "CODE_SIP_PROXY_AUTHENTICATION_REQUIRED");
+ sImsCodeMap.put(CODE_SIP_REQUEST_ENTITY_TOO_LARGE, "CODE_SIP_REQUEST_ENTITY_TOO_LARGE");
+ sImsCodeMap.put(CODE_SIP_REQUEST_URI_TOO_LARGE, "CODE_SIP_REQUEST_URI_TOO_LARGE");
+ sImsCodeMap.put(CODE_SIP_EXTENSION_REQUIRED, "CODE_SIP_EXTENSION_REQUIRED");
+ sImsCodeMap.put(CODE_SIP_INTERVAL_TOO_BRIEF, "CODE_SIP_INTERVAL_TOO_BRIEF");
+ sImsCodeMap.put(CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST,
+ "CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST");
+ sImsCodeMap.put(CODE_SIP_LOOP_DETECTED, "CODE_SIP_LOOP_DETECTED");
+ sImsCodeMap.put(CODE_SIP_TOO_MANY_HOPS, "CODE_SIP_TOO_MANY_HOPS");
+ sImsCodeMap.put(CODE_SIP_AMBIGUOUS, "CODE_SIP_AMBIGUOUS");
+ sImsCodeMap.put(CODE_SIP_REQUEST_PENDING, "CODE_SIP_REQUEST_PENDING");
+ sImsCodeMap.put(CODE_SIP_UNDECIPHERABLE, "CODE_SIP_UNDECIPHERABLE");
+ sImsCodeMap.put(CODE_MEDIA_INIT_FAILED, "CODE_MEDIA_INIT_FAILED");
+ sImsCodeMap.put(CODE_MEDIA_NO_DATA, "CODE_MEDIA_NO_DATA");
+ sImsCodeMap.put(CODE_MEDIA_NOT_ACCEPTABLE, "CODE_MEDIA_NOT_ACCEPTABLE");
+ sImsCodeMap.put(CODE_MEDIA_UNSPECIFIED, "CODE_MEDIA_UNSPECIFIED");
+ sImsCodeMap.put(CODE_USER_TERMINATED, "CODE_USER_TERMINATED");
+ sImsCodeMap.put(CODE_USER_NOANSWER, "CODE_USER_NOANSWER");
+ sImsCodeMap.put(CODE_USER_IGNORE, "CODE_USER_IGNORE");
+ sImsCodeMap.put(CODE_USER_DECLINE, "CODE_USER_DECLINE");
+ sImsCodeMap.put(CODE_LOW_BATTERY, "CODE_LOW_BATTERY");
+ sImsCodeMap.put(CODE_BLACKLISTED_CALL_ID, "CODE_BLACKLISTED_CALL_ID");
+ sImsCodeMap.put(CODE_USER_TERMINATED_BY_REMOTE, "CODE_USER_TERMINATED_BY_REMOTE");
+ sImsCodeMap.put(CODE_USER_REJECTED_SESSION_MODIFICATION,
+ "CODE_USER_REJECTED_SESSION_MODIFICATION");
+ sImsCodeMap.put(CODE_USER_CANCELLED_SESSION_MODIFICATION,
+ "CODE_USER_CANCELLED_SESSION_MODIFICATION");
+ sImsCodeMap.put(CODE_SESSION_MODIFICATION_FAILED, "CODE_SESSION_MODIFICATION_FAILED");
+ sImsCodeMap.put(CODE_UT_NOT_SUPPORTED, "CODE_UT_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_UT_SERVICE_UNAVAILABLE, "CODE_UT_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_UT_OPERATION_NOT_ALLOWED, "CODE_UT_OPERATION_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_UT_NETWORK_ERROR, "CODE_UT_NETWORK_ERROR");
+ sImsCodeMap.put(CODE_UT_CB_PASSWORD_MISMATCH, "CODE_UT_CB_PASSWORD_MISMATCH");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_DIAL, "CODE_UT_SS_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_USSD, "CODE_UT_SS_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_SS, "CODE_UT_SS_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO, "CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_ECBM_NOT_SUPPORTED, "CODE_ECBM_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_MULTIENDPOINT_NOT_SUPPORTED, "CODE_MULTIENDPOINT_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_REGISTRATION_ERROR, "CODE_REGISTRATION_ERROR");
+ sImsCodeMap.put(CODE_ANSWERED_ELSEWHERE, "CODE_ANSWERED_ELSEWHERE");
+ sImsCodeMap.put(CODE_CALL_PULL_OUT_OF_SYNC, "CODE_CALL_PULL_OUT_OF_SYNC");
+ sImsCodeMap.put(CODE_CALL_END_CAUSE_CALL_PULL, "CODE_CALL_END_CAUSE_CALL_PULL");
+ sImsCodeMap.put(CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
+ "CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_REJECTED_ELSEWHERE, "CODE_REJECTED_ELSEWHERE");
+ sImsCodeMap.put(CODE_SUPP_SVC_FAILED, "CODE_SUPP_SVC_FAILED");
+ sImsCodeMap.put(CODE_SUPP_SVC_CANCELLED, "CODE_SUPP_SVC_CANCELLED");
+ sImsCodeMap.put(CODE_SUPP_SVC_REINVITE_COLLISION, "CODE_SUPP_SVC_REINVITE_COLLISION");
+ sImsCodeMap.put(CODE_IWLAN_DPD_FAILURE, "CODE_IWLAN_DPD_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_ESTABLISH_FAILURE, "CODE_EPDG_TUNNEL_ESTABLISH_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_REKEY_FAILURE, "CODE_EPDG_TUNNEL_REKEY_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_LOST_CONNECTION, "CODE_EPDG_TUNNEL_LOST_CONNECTION");
+ sImsCodeMap.put(CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
+ "CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED");
+ sImsCodeMap.put(CODE_REMOTE_CALL_DECLINE, "CODE_REMOTE_CALL_DECLINE");
+ sImsCodeMap.put(CODE_DATA_LIMIT_REACHED, "CODE_DATA_LIMIT_REACHED");
+ sImsCodeMap.put(CODE_DATA_DISABLED, "CODE_DATA_DISABLED");
+ sImsCodeMap.put(CODE_WIFI_LOST, "CODE_WIFI_LOST");
+ sImsCodeMap.put(CODE_IKEV2_AUTH_FAILURE, "CODE_IKEV2_AUTH_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_OFF, "CODE_RADIO_OFF");
+ sImsCodeMap.put(CODE_NO_VALID_SIM, "CODE_NO_VALID_SIM");
+ sImsCodeMap.put(CODE_RADIO_INTERNAL_ERROR, "CODE_RADIO_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_NETWORK_RESP_TIMEOUT, "CODE_NETWORK_RESP_TIMEOUT");
+ sImsCodeMap.put(CODE_NETWORK_REJECT, "CODE_NETWORK_REJECT");
+ sImsCodeMap.put(CODE_RADIO_ACCESS_FAILURE, "CODE_RADIO_ACCESS_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_LINK_FAILURE, "CODE_RADIO_LINK_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_LINK_LOST, "CODE_RADIO_LINK_LOST");
+ sImsCodeMap.put(CODE_RADIO_UPLINK_FAILURE, "CODE_RADIO_UPLINK_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_SETUP_FAILURE, "CODE_RADIO_SETUP_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_RELEASE_NORMAL, "CODE_RADIO_RELEASE_NORMAL");
+ sImsCodeMap.put(CODE_RADIO_RELEASE_ABNORMAL, "CODE_RADIO_RELEASE_ABNORMAL");
+ sImsCodeMap.put(CODE_ACCESS_CLASS_BLOCKED, "CODE_ACCESS_CLASS_BLOCKED");
+ sImsCodeMap.put(CODE_NETWORK_DETACH, "CODE_NETWORK_DETACH");
+ sImsCodeMap.put(CODE_SIP_ALTERNATE_EMERGENCY_CALL, "CODE_SIP_ALTERNATE_EMERGENCY_CALL");
+ sImsCodeMap.put(CODE_UNOBTAINABLE_NUMBER, "CODE_UNOBTAINABLE_NUMBER");
+ sImsCodeMap.put(CODE_NO_CSFB_IN_CS_ROAM, "CODE_NO_CSFB_IN_CS_ROAM");
+ sImsCodeMap.put(CODE_REJECT_UNKNOWN, "CODE_REJECT_UNKNOWN");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_WAITING_DISABLED,
+ "CODE_REJECT_ONGOING_CALL_WAITING_DISABLED");
+ sImsCodeMap.put(CODE_REJECT_CALL_ON_OTHER_SUB, "CODE_REJECT_CALL_ON_OTHER_SUB");
+ sImsCodeMap.put(CODE_REJECT_1X_COLLISION, "CODE_REJECT_1X_COLLISION");
+ sImsCodeMap.put(CODE_REJECT_SERVICE_NOT_REGISTERED, "CODE_REJECT_SERVICE_NOT_REGISTERED");
+ sImsCodeMap.put(CODE_REJECT_CALL_TYPE_NOT_ALLOWED, "CODE_REJECT_CALL_TYPE_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_E911_CALL, "CODE_REJECT_ONGOING_E911_CALL");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_SETUP, "CODE_REJECT_ONGOING_CALL_SETUP");
+ sImsCodeMap.put(CODE_REJECT_MAX_CALL_LIMIT_REACHED, "CODE_REJECT_MAX_CALL_LIMIT_REACHED");
+ sImsCodeMap.put(CODE_REJECT_UNSUPPORTED_SIP_HEADERS, "CODE_REJECT_UNSUPPORTED_SIP_HEADERS");
+ sImsCodeMap.put(CODE_REJECT_UNSUPPORTED_SDP_HEADERS, "CODE_REJECT_UNSUPPORTED_SDP_HEADERS");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_TRANSFER, "CODE_REJECT_ONGOING_CALL_TRANSFER");
+ sImsCodeMap.put(CODE_REJECT_INTERNAL_ERROR, "CODE_REJECT_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_REJECT_QOS_FAILURE, "CODE_REJECT_QOS_FAILURE");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_HANDOVER, "CODE_REJECT_ONGOING_HANDOVER");
+ sImsCodeMap.put(CODE_REJECT_VT_TTY_NOT_ALLOWED, "CODE_REJECT_VT_TTY_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_UPGRADE, "CODE_REJECT_ONGOING_CALL_UPGRADE");
+ sImsCodeMap.put(CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED,
+ "CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CONFERENCE_CALL, "CODE_REJECT_ONGOING_CONFERENCE_CALL");
+ sImsCodeMap.put(CODE_REJECT_VT_AVPF_NOT_ALLOWED, "CODE_REJECT_VT_AVPF_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_ENCRYPTED_CALL, "CODE_REJECT_ONGOING_ENCRYPTED_CALL");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CS_CALL, "CODE_REJECT_ONGOING_CS_CALL");
+ sImsCodeMap.put(CODE_RETRY_ON_IMS_WITHOUT_RTT, "CODE_RETRY_ON_IMS_WITHOUT_RTT");
+ sImsCodeMap.put(CODE_OEM_CAUSE_1, "CODE_OEM_CAUSE_1");
+ sImsCodeMap.put(CODE_OEM_CAUSE_2, "CODE_OEM_CAUSE_2");
+ sImsCodeMap.put(CODE_OEM_CAUSE_3, "CODE_OEM_CAUSE_3");
+ sImsCodeMap.put(CODE_OEM_CAUSE_4, "CODE_OEM_CAUSE_4");
+ sImsCodeMap.put(CODE_OEM_CAUSE_5, "CODE_OEM_CAUSE_5");
+ sImsCodeMap.put(CODE_OEM_CAUSE_6, "CODE_OEM_CAUSE_6");
+ sImsCodeMap.put(CODE_OEM_CAUSE_7, "CODE_OEM_CAUSE_7");
+ sImsCodeMap.put(CODE_OEM_CAUSE_8, "CODE_OEM_CAUSE_8");
+ sImsCodeMap.put(CODE_OEM_CAUSE_9, "CODE_OEM_CAUSE_9");
+ sImsCodeMap.put(CODE_OEM_CAUSE_10, "CODE_OEM_CAUSE_10");
+ sImsCodeMap.put(CODE_OEM_CAUSE_11, "CODE_OEM_CAUSE_11");
+ sImsCodeMap.put(CODE_OEM_CAUSE_12, "CODE_OEM_CAUSE_12");
+ sImsCodeMap.put(CODE_OEM_CAUSE_13, "CODE_OEM_CAUSE_13");
+ sImsCodeMap.put(CODE_OEM_CAUSE_14, "CODE_OEM_CAUSE_14");
+ sImsCodeMap.put(CODE_OEM_CAUSE_15, "CODE_OEM_CAUSE_15");
+ }
+
/**
* Network string error messages.
* mExtraMessage may have these values.
@@ -1203,7 +1394,9 @@
@NonNull
@Override
public String toString() {
- return "ImsReasonInfo :: {" + mCode + ", " + mExtraCode + ", " + mExtraMessage + "}";
+ String imsCode = (sImsCodeMap.containsKey(mCode)) ? sImsCodeMap.get(mCode) : "UNKNOWN_CODE";
+ return "ImsReasonInfo :: {" + mCode + " : " + imsCode + ", "
+ + mExtraCode + ", " + mExtraMessage + "}";
}
@Override
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
index aae6f92..0c72646 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
@@ -89,7 +89,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in Integer format.
@@ -102,7 +102,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in String format.
@@ -114,7 +114,7 @@
/**
* Gets the value of the specified IMS feature item for specified network type.
- * This operation gets the feature config value from the master storage (i.e. final
+ * This operation gets the feature config value from the main storage (i.e. final
* value). Asynchronous non-blocking call.
*
* @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -127,7 +127,7 @@
/**
* Sets the value for IMS feature item for specified network type.
- * This operation stores the user setting in setting db from which master db
+ * This operation stores the user setting in setting db from which main db
* is derived.
*
* @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -268,7 +268,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
@@ -292,7 +292,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index 73ba0e3..8f738d2 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -439,8 +439,8 @@
* Transfer an established call to given number
*
* @param number number to transfer the call
- * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
- * if {@code False} it indicates Blind transfer.
+ * @param isConfirmationRequired if {@code True}, indicates a confirmed transfer,
+ * if {@code False} it indicates an unconfirmed transfer.
* @hide
*/
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 6a2638b..4ef44d3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -142,7 +142,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item integer key
@@ -167,7 +167,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
diff --git a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
index 689becd..17adede 100644
--- a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
+++ b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
@@ -91,7 +91,7 @@
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
- // Sanity check our security
+ // Correctness check our security
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index 0466efc..ab14e82 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -153,8 +153,8 @@
* Transfer an established call to given number
*
* @param number number to transfer the call
- * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
- * if {@code False} it indicates Blind transfer.
+ * @param isConfirmationRequired if {@code True}, indicates a confirmed transfer,
+ * if {@code False} it indicates an unconfirmed transfer.
*/
void transfer(String number, boolean isConfirmationRequired);
diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl
index 7324814..1a14e87 100644
--- a/telephony/java/com/android/ims/internal/IImsConfig.aidl
+++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl
@@ -49,7 +49,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in Integer format.
@@ -60,7 +60,7 @@
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in String format.
@@ -70,7 +70,7 @@
/**
* Gets the value of the specified IMS feature item for specified network type.
- * This operation gets the feature config value from the master storage (i.e. final
+ * This operation gets the feature config value from the main storage (i.e. final
* value). Asynchronous non-blocking call.
*
* @param feature. as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -82,7 +82,7 @@
/**
* Sets the value for IMS feature item for specified network type.
- * This operation stores the user setting in setting db from which master db
+ * This operation stores the user setting in setting db from which main db
* is dervied.
*
* @param feature. as defined in com.android.ims.ImsConfig#FeatureConstants.
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 542e08d..a34e474 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -479,7 +479,7 @@
length = dis.readUnsignedByte();
addr.numberOfDigits = length;
- // sanity check on the length
+ // Correctness check on the length
if (length > pdu.length) {
throw new RuntimeException(
"createFromPdu: Invalid pdu, addr.numberOfDigits " + length
@@ -496,7 +496,7 @@
//encoded BearerData:
bearerDataLength = dis.readInt();
- // sanity check on the length
+ // Correctness check on the length
if (bearerDataLength > pdu.length) {
throw new RuntimeException(
"createFromPdu: Invalid pdu, bearerDataLength " + bearerDataLength
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 7e31c46..e3df903 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -353,7 +353,7 @@
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
- // properly later on encodedMessage sanity check.
+ // properly later on encodedMessage correctness check.
if (bo == null) return ret;
// User Data (and length)
@@ -535,7 +535,7 @@
scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
- // properly later on encodedMessage sanity check.
+ // properly later on encodedMessage correctness check.
if (bo == null) return ret;
// TP-Data-Coding-Scheme
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
similarity index 98%
rename from tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
rename to tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
index 2df0024..56db4f9 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
@@ -35,7 +35,7 @@
import java.util.Random;
import java.util.concurrent.TimeUnit;
-public class DummyBlobData {
+public class FakeBlobData {
private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
private final Random mRandom;
@@ -47,7 +47,7 @@
byte[] mFileDigest;
long mExpiryTimeMs;
- private DummyBlobData(Builder builder) {
+ private FakeBlobData(Builder builder) {
mRandom = new Random(builder.getRandomSeed());
mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
mFileSize = builder.getFileSize();
@@ -116,8 +116,8 @@
return mExpiryDurationMs;
}
- public DummyBlobData build() {
- return new DummyBlobData(this);
+ public FakeBlobData build() {
+ return new FakeBlobData(this);
}
}
diff --git a/tests/BootImageProfileTest/OWNERS b/tests/BootImageProfileTest/OWNERS
index 657b3f2..7ee0d9a 100644
--- a/tests/BootImageProfileTest/OWNERS
+++ b/tests/BootImageProfileTest/OWNERS
@@ -1,4 +1,4 @@
-mathieuc@google.com
calin@google.com
+mathieuc@google.com
+ngeoffray@google.com
yawanng@google.com
-sehr@google.com
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 5161fba..952997e 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -24,6 +24,7 @@
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
+ "androidx.test.ext.junit",
"flickertestapplib",
"flickerlib",
"truth-prebuilt",
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
new file mode 100644
index 0000000..c1a3ed69
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -0,0 +1,153 @@
+/*
+ * 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 com.android.server.wm.flicker.dsl.EventLogAssertion
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+import com.android.server.wm.flicker.helpers.WindowUtils
+
+@JvmOverloads
+fun WmAssertion.statusBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun WmAssertion.navBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", enabled, bugId) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ } else {
+ start("noUncoveredRegions_StartingPos") {
+ this.coversAtLeastRegion(startingBounds)
+ }
+ end("noUncoveredRegions_EndingPos") {
+ this.coversAtLeastRegion(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ }
+
+ if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ }
+}
+
+fun EventLogAssertion.focusChanges(
+ vararg windows: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusDoesNotChange()
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
deleted file mode 100644
index b69e6a9..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
+++ /dev/null
@@ -1,446 +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.app.Instrumentation
-import android.content.Context
-import android.content.Intent
-import android.os.RemoteException
-import android.os.SystemClock
-import android.platform.helpers.IAppHelper
-import android.util.Rational
-import android.view.Surface
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.PipAppHelper
-
-/**
- * Collection of common transitions which can be used to test different apps or scenarios.
- */
-internal object CommonTransitions {
- private const val ITERATIONS = 1
- private const val APP_LAUNCH_TIMEOUT: Long = 10000
- private fun setRotation(device: UiDevice, 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 rotation Initial screen rotation
- *
- * @return test tag with pattern <NAME>__<APP>__<ROTATION>
- </ROTATION></APP></NAME> */
- private 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> */
- private 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> */
- private fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int,
- app2: IAppHelper?,
- extraInfo: String
- ): String {
- val testTag = StringBuilder()
- testTag.append(testName)
- .append("__")
- .append(app.launcherName)
- if (app2 != null) {
- testTag.append("-")
- .append(app2.launcherName)
- }
- testTag.append("__")
- .append(Surface.rotationToString(beginRotation))
- if (endRotation != beginRotation) {
- testTag.append("-")
- .append(Surface.rotationToString(endRotation))
- }
- if (extraInfo.isNotEmpty()) {
- testTag.append("__")
- .append(extraInfo)
- }
- return testTag.toString()
- }
-
- fun openAppWarm(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("openAppWarm", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBeforeAll { testApp.open() }
- .runBefore { device.pressHome() }
- .runBefore { device.waitForIdle() }
- .runBefore { setRotation(device, beginRotation) }
- .run { testApp.open() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun closeAppWithBackKey(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("closeAppWithBackKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .run { device.pressBack() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun closeAppWithHomeKey(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("closeAppWithHomeKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .run { device.pressHome() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun openAppCold(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("openAppCold", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBefore { testApp.exit() }
- .runBefore { device.waitForIdle() }
- .run { testApp.open() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun changeAppRotation(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- endRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("changeAppRotation", testApp, beginRotation, endRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { testApp.open() }
- .runBefore { setRotation(device, beginRotation) }
- .run { setRotation(device, endRotation) }
- .runAfterAll { testApp.exit() }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun changeAppRotation(
- intent: Intent,
- intentId: String,
- context: Context,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- endRotation: Int
- ): TransitionRunner.TransitionBuilder {
- val testTag = "changeAppRotation_" + intentId + "_" +
- Surface.rotationToString(beginRotation) + "_" +
- Surface.rotationToString(endRotation)
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll {
- context.startActivity(intent)
- device.wait(Until.hasObject(By.pkg(intent.component?.packageName)
- .depth(0)), APP_LAUNCH_TIMEOUT)
- }
- .runBefore { setRotation(device, beginRotation) }
- .run { setRotation(device, endRotation) }
- .runAfterAll { AutomationUtils.stopPackage(context, intent.component?.packageName) }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun appToSplitScreen(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("appToSplitScreen", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { SystemClock.sleep(500) }
- .run { AutomationUtils.launchSplitScreen(device) }
- .runAfter { AutomationUtils.exitSplitScreen(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun splitScreenToLauncher(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("splitScreenToLauncher", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { AutomationUtils.launchSplitScreen(device) }
- .run { AutomationUtils.exitSplitScreen(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextSetFocus(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextSetFocus", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.openIME(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun resizeSplitScreen(
- testAppTop: IAppHelper,
- testAppBottom: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- startRatio: Rational,
- stopRatio: Rational
- ): TransitionRunner.TransitionBuilder {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- val testTag = buildTestTag("resizeSplitScreen", testAppTop, beginRotation,
- beginRotation, testAppBottom, description)
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBeforeAll { AutomationUtils.clearRecents(instrumentation) }
- .runBefore { testAppBottom.open() }
- .runBefore { device.pressHome() }
- .runBefore { testAppTop.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { AutomationUtils.launchSplitScreen(device) }
- .runBefore {
- val snapshot = device.findObject(
- By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- }
- .runBefore { testAppBottom.openIME(device) }
- .runBefore { device.pressBack() }
- .runBefore { AutomationUtils.resizeSplitScreen(device, startRatio) }
- .run { AutomationUtils.resizeSplitScreen(device, stopRatio) }
- .runAfter { AutomationUtils.exitSplitScreen(device) }
- .runAfter { device.pressHome() }
- .runAfterAll { testAppTop.exit() }
- .runAfterAll { testAppBottom.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextLoseFocusToHome(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextLoseFocusToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { testApp.openIME(device) }
- .run { device.pressHome() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextLoseFocusToApp(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextLoseFocusToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { testApp.openIME(device) }
- .run { device.pressBack() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun enterPipMode(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("enterPipMode", testApp, beginRotation))
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .runAfter { testApp.closePipWindow(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun exitPipModeToHome(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("exitPipModeToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .run { testApp.closePipWindow(device) }
- .run { device.waitForIdle() }
- .run { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun exitPipModeToApp(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("exitPipModeToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .run { device.pressHome() }
- .run { setRotation(device, beginRotation) }
- .run { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .run { AutomationUtils.expandPipWindow(device) }
- .run { device.waitForIdle() }
- .run { testApp.exit() }
- .repeat(ITERATIONS)
- }
-}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
deleted file mode 100644
index 43cfdff..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
+++ /dev/null
@@ -1,190 +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.platform.helpers.IAppHelper
-import android.util.Rational
-import android.view.Surface
-import androidx.test.InstrumentationRegistry
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.PipAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-
-/**
- * Tests to help debug individual transitions, capture video recordings and create test cases.
- *
- * Not actual tests
- */
-@LargeTest
-@FlakyTest
-@RunWith(AndroidJUnit4::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DebugTest {
- private val instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp: IAppHelper = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- private val uiDevice = UiDevice.getInstance(instrumentation)
-
- /**
- * atest FlickerTests:DebugTest#openAppCold
- */
- @Test
- fun openAppCold() {
- CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppWarm
- */
- @Test
- fun openAppWarm() {
- CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
- */
- @Test
- fun changeOrientationFromNaturalToLeft() {
- CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice, Surface.ROTATION_0,
- Surface.ROTATION_270).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithBackKey
- */
- @Test
- fun closeAppWithBackKey() {
- CommonTransitions.closeAppWithBackKey(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithHomeKey
- */
- @Test
- fun closeAppWithHomeKey() {
- CommonTransitions.closeAppWithHomeKey(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppToSplitScreen
- */
- @Test
- fun openAppToSplitScreen() {
- CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#splitScreenToLauncher
- */
- @Test
- fun splitScreenToLauncher() {
- CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#resizeSplitScreen
- */
- @Test
- fun resizeSplitScreen() {
- val bottomApp = ImeAppHelper(instrumentation)
- CommonTransitions.resizeSplitScreen(
- testApp,
- bottomApp,
- instrumentation,
- uiDevice,
- Surface.ROTATION_0,
- Rational(1, 3), Rational(2, 3)
- ).includeJankyRuns().build().run()
- }
- // IME tests
- /**
- * atest FlickerTests:DebugTest#editTextSetFocus
- */
- @Test
- fun editTextSetFocus() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextSetFocus(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToHome
- */
- @Test
- fun editTextLoseFocusToHome() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToApp
- */
- @Test
- fun editTextLoseFocusToApp() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build().run()
- }
- // PIP tests
- /**
- * atest FlickerTests:DebugTest#enterPipMode
- */
- @Test
- fun enterPipMode() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.enterPipMode(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToHome
- */
- @Test
- fun exitPipModeToHome() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.exitPipModeToHome(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToApp
- */
- @Test
- fun exitPipModeToApp() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.exitPipModeToApp(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build().run()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
index d7586d0..abe7dbc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
@@ -16,15 +16,12 @@
package com.android.server.wm.flicker
+import android.os.RemoteException
+import android.os.SystemClock
import android.platform.helpers.IAppHelper
-import android.util.Log
-import androidx.test.InstrumentationRegistry
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import com.google.common.truth.Truth
-import org.junit.After
-import org.junit.AfterClass
-import org.junit.Before
/**
* Base class of all Flicker test that performs common functions for all flicker tests:
@@ -37,101 +34,96 @@
* - Fails tests if results are not available for any test due to jank.
*/
abstract class FlickerTestBase {
- lateinit var testApp: IAppHelper
- open val instrumentation by lazy {
+ val instrumentation by lazy {
InstrumentationRegistry.getInstrumentation()
}
val uiDevice by lazy {
UiDevice.getInstance(instrumentation)
}
- lateinit var tesults: List<TransitionResult>
- private var lastResult: TransitionResult? = null
/**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- fun run(transition: TransitionRunner) {
- if (transitionResults.containsKey(transition.testTag)) {
- tesults = transitionResults[transition.testTag]
- ?: throw IllegalStateException("Results do not contain test tag " +
- transition.testTag)
- return
+ * 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}"
}
- tesults = transition.run().results
- /* Fail if we don't have any results due to jank */
- Truth.assertWithMessage("No results to test because all transition runs were invalid " +
- "because of Jank").that(tesults).isNotEmpty()
- transitionResults[transition.testTag] = tesults
- }
-
- /**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- @Before
- fun runTransition() {
- run(transitionToRun)
- }
-
- /**
- * Gets the transition that will be executed
- */
- abstract val transitionToRun: TransitionRunner
-
- /**
- * Goes through a list of transition results and checks assertions on each result.
- */
- fun checkResults(assertion: (TransitionResult) -> Unit) {
- for (result in tesults) {
- lastResult = result
- assertion(result)
+ testTag += "__${Surface.rotationToString(beginRotation)}"
+ if (endRotation != beginRotation) {
+ testTag += "-${Surface.rotationToString(endRotation)}"
}
- lastResult = null
+ if (extraInfo.isNotEmpty()) {
+ testTag += "__$extraInfo"
+ }
+ return testTag
}
- /**
- * Kludge to mark a file for saving. If `checkResults` fails, the last result is not
- * cleared. This indicates the assertion failed for the result, so mark it for saving.
- */
- @After
- fun markArtifactsForSaving() {
- lastResult?.flagForSaving()
+ 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 TAG = "FLICKER"
const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
- private val transitionResults = mutableMapOf<String, List<TransitionResult>>()
-
- /**
- * Teardown any system settings and clean up test artifacts from the file system.
- *
- * Note: test artifacts for failed tests will remain on the device.
- */
- @AfterClass
- @JvmStatic
- fun teardown() {
- AutomationUtils.setDefaultWait()
- transitionResults.values
- .flatten()
- .forEach {
- if (it.canDelete()) {
- it.delete()
- } else {
- if (it.layersTraceExists()) {
- Log.e(TAG, "Layers trace saved to ${it.layersTracePath}")
- }
- if (it.windowManagerTraceExists()) {
- Log.e(TAG,
- "WindowManager trace saved to ${it.windowManagerTracePath}")
- }
- if (it.screenCaptureVideoExists()) {
- Log.e(TAG,
- "Screen capture video saved to ${it.screenCaptureVideoPath()}")
- }
- }
- }
- }
}
-}
+}
\ 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
index 1f8150c..e7d1f8e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
@@ -17,52 +17,20 @@
package com.android.server.wm.flicker
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import org.junit.Test
import org.junit.runners.Parameterized
abstract class NonRotationTestBase(
- beginRotationName: String,
- protected val beginRotation: Int
+ protected val rotationName: String,
+ protected val rotation: Int
) : FlickerTestBase() {
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkCoveredRegion_noUncoveredRegions() {
- val displayBounds = WindowUtils.getDisplayBounds(beginRotation)
- checkResults {
- LayersTraceSubject.assertThat(it).coversRegion(
- displayBounds).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
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)
- val params: MutableCollection<Array<Any>> = ArrayList()
- for (begin in supportedRotations) {
- params.add(arrayOf(Surface.rotationToString(begin), begin))
- }
- return params
+ 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
index dfc3c07..3b67727 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
@@ -17,8 +17,6 @@
package com.android.server.wm.flicker
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import org.junit.Test
import org.junit.runners.Parameterized
abstract class RotationTestBase(
@@ -27,82 +25,7 @@
protected val beginRotation: Int,
protected val endRotation: Int
) : FlickerTestBase() {
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @Test
- fun checkPosition_navBarLayerRotatesAndScales() {
- val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
- val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
- if (startingPos == endingPos) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .forAllEntries()
- }
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning()
- }
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- .atTheEnd()
- }
- }
- }
-
- @Test
- fun checkPosition_statusBarLayerRotatesScales() {
- val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
- val endingPos = WindowUtils.getStatusBarPosition(endRotation)
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning()
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
companion object {
- const val SCREENSHOT_LAYER = "RotationLayer"
-
@Parameterized.Parameters(name = "{0}-{1}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
@@ -123,4 +46,4 @@
return params
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
index e579533..7147577 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
@@ -17,14 +17,15 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
import com.android.server.wm.flicker.StandardAppHelper
abstract class FlickerAppHelper(
instr: Instrumentation,
- launcherName: String
-) : StandardAppHelper(instr, sFlickerPackage, launcherName) {
+ launcherName: String,
+ launcherStrategy: ILauncherStrategy
+) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
companion object {
- var sFindTimeout = 10000
var sFlickerPackage = "com.android.server.wm.flicker.testapp"
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 979cbea..c1b7657 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,6 +17,8 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
@@ -24,17 +26,26 @@
open class ImeAppHelper(
instr: Instrumentation,
- launcherName: String = "ImeApp"
-) : FlickerAppHelper(instr, launcherName) {
+ launcherName: String = "ImeApp",
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
open fun openIME(device: UiDevice) {
val editText = device.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
- AutomationUtils.FIND_TIMEOUT)
+ FIND_TIMEOUT)
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
- if (!AutomationUtils.waitForIME(device)) {
+ if (!device.waitForIME()) {
Assert.fail("IME did not appear")
}
}
+
+ open fun closeIME(device: UiDevice) {
+ device.pressBack()
+ // Using only the AccessibilityInfo it is not possible to identify if the IME is active
+ device.waitForIdle(1000)
+ }
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index daee810..d10bb1e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -17,20 +17,27 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import org.junit.Assert
-class PipAppHelper(instr: Instrumentation) : FlickerAppHelper(instr, "PipApp") {
+class PipAppHelper(
+ instr: Instrumentation,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
fun clickEnterPipButton(device: UiDevice) {
val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
Assert.assertNotNull("Pip button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", enterPipButton)
enterPipButton.click()
- AutomationUtils.hasPipWindow(device)
+ device.hasPipWindow()
}
fun closePipWindow(device: UiDevice) {
- AutomationUtils.closePipWindow(device)
+ device.closePipWindow()
}
}
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 814cdcf..80d0394 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,11 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+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.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
@@ -35,33 +43,52 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : CloseImeWindowToAppTest(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppAutoFocusHelper(instrumentation)
- }
+ rotationName: String,
+ rotation: Int
+) : CloseImeWindowToAppTest(rotationName, rotation) {
+ override val testApp: ImeAppHelper
+ get() = ImeAppAutoFocusHelper(instrumentation)
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppAutoFocusHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
- @FlakyTest(bugId = 141458352)
@Test
- override fun checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible()
- }
+ 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)
+ }
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeAppLayerIsAlwaysVisible() {
- super.checkVisibility_imeAppLayerIsAlwaysVisible()
- }
-
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeAppWindowIsAlwaysVisible() {
- super.checkVisibility_imeAppWindowIsAlwaysVisible()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ imeLayerBecomesInvisible(bugId = 141458352)
+ imeAppLayerIsAlwaysVisible(testApp, bugId = 141458352)
+ }
+ }
+ }
}
}
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 c2025b6..2e4d390 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
@@ -16,11 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+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.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
@@ -35,33 +43,53 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : CloseImeWindowToHomeTest(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppAutoFocusHelper(instrumentation)
- }
+ rotationName: String,
+ rotation: Int
+) : CloseImeWindowToHomeTest(rotationName, rotation) {
+ override val testApp: ImeAppHelper
+ get() = ImeAppAutoFocusHelper(instrumentation)
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppAutoFocusHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
- @FlakyTest(bugId = 141458352)
@Test
- override fun checkVisibility_imeWindowBecomesInvisible() {
- super.checkVisibility_imeWindowBecomesInvisible()
- }
+ 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)
+ }
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible()
- }
-
- @FlakyTest(bugId = 157449248)
- @Test
- override fun checkVisibility_imeAppWindowBecomesInvisible() {
- super.checkVisibility_imeAppWindowBecomesInvisible()
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, 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 b38262e..67c46d3 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
@@ -16,14 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+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.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
@@ -38,49 +43,51 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
- @FlakyTest
- @Test
- open fun checkVisibility_imeLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ open val testApp = ImeAppHelper(instrumentation)
@Test
- open fun checkVisibility_imeAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .forAllEntries()
+ 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)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ imeLayerBecomesInvisible(enabled = false)
+ imeAppLayerIsAlwaysVisible(testApp)
+ }
+ }
}
}
-
- @Test
- open fun checkVisibility_imeAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
-
- companion object {
- const val IME_WINDOW_TITLE = "InputMethod"
- }
-}
+}
\ 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 ca04bab..1c0da4f 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
@@ -16,20 +16,26 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.openQuickstep
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+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.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 IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
@@ -38,67 +44,60 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ open val testApp = ImeAppHelper(instrumentation)
@Test
- open fun checkVisibility_imeWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .forAllEntries()
+ 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)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
+ imeLayerBecomesInvisible(bugId = 153739621)
+ imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ }
+ }
}
}
-
- @FlakyTest(bugId = 153739621)
- @Test
- open fun checkVisibility_imeLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 153739621)
- @Test
- fun checkVisibility_imeAppLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- .forAllEntries()
- }
- }
-
- @Test
- open fun checkVisibility_imeAppWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
-
- companion object {
- const val IME_WINDOW_TITLE: String = "InputMethod"
- }
-}
+}
\ 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/ImeAssertions.kt
new file mode 100644
index 0000000..b2be54f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.ime
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+
+const val IME_WINDOW_TITLE = "InputMethod"
+
+@JvmOverloads
+fun LayersAssertion.imeLayerBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeLayerBecomesVisible", enabled, bugId) {
+ this.hidesLayer(IME_WINDOW_TITLE)
+ .then()
+ .showsLayer(IME_WINDOW_TITLE)
+ }
+}
+
+fun LayersAssertion.imeLayerBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeLayerBecomesInvisible", enabled, bugId) {
+ this.showsLayer(IME_WINDOW_TITLE)
+ .then()
+ .hidesLayer(IME_WINDOW_TITLE)
+ }
+}
+
+fun LayersAssertion.imeAppLayerIsAlwaysVisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(testApp.getPackage())
+ }
+}
+
+fun WmAssertion.imeAppWindowIsAlwaysVisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ }
+}
+
+fun WmAssertion.imeWindowBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeWindowBecomesInvisible", enabled, bugId) {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun WmAssertion.imeAppWindowBecomesInvisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppWindowBecomesInvisible", enabled, bugId) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .appWindowNotOnTop(testApp.getPackage())
+ }
+}
+
+fun LayersAssertion.imeAppLayerBecomesInvisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppLayerBecomesInvisible", enabled, bugId) {
+ this.skipUntilFirstAssertion()
+ .showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ }
+}
\ No newline at end of file
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 c7731f3..5874a07 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
@@ -16,13 +16,19 @@
package com.android.server.wm.flicker.ime
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+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.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
@@ -37,38 +43,58 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextSetFocus(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_imeWindowBecomesVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ fun test() {
+ val testApp = ImeAppHelper(instrumentation)
- @Test
- fun checkVisibility_imeLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
- .forAllEntries()
+ 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()
+ }
+ }
}
}
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 88b8854..62337e9 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
@@ -16,14 +16,18 @@
package com.android.server.wm.flicker.launch
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+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.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
@@ -38,50 +42,53 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : OpenAppTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_wallpaperWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries()
- }
- }
+ 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()
+ }
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
+ 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()
+ statusBarLayerIsAlwaysVisible(enabled = false)
+ wallpaperLayerBecomesInvisible()
+ }
- @Test
- fun checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- .forAllEntries()
+ 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
new file mode 100644
index 0000000..7d70812
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.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 f0bc3f0..9a8e37b 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,14 +16,19 @@
package com.android.server.wm.flicker.launch
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
-import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+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.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
@@ -38,50 +43,60 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
+ rotationName: String,
+ rotation: Int
+) : OpenAppTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ 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)
+ }
- @Test
- fun checkVisibility_wallpaperBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries()
+ 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()
+ statusBarLayerIsAlwaysVisible(enabled = false)
+ wallpaperLayerBecomesInvisible()
+ }
+
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
}
}
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
-
- @Test
- fun checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- .forAllEntries()
- }
- }
-}
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..4acd975
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.pip
+
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.LargeTest
+import com.android.server.wm.flicker.dsl.flicker
+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.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.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 Pip launch.
+ * To run this test: `atest FlickerTests:PipToAppTest`
+ */
+@LargeTest
+@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)
+ }
+ }
+ }
+ }
+ }
+
+ 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) }
+ }
+ }
+}
\ 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/PipTestBase.kt
index 79321f9..691db7fb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
@@ -16,66 +16,16 @@
package com.android.server.wm.flicker.pip
-import androidx.test.InstrumentationRegistry
-import androidx.test.filters.LargeTest
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
import com.android.server.wm.flicker.helpers.PipAppHelper
-import org.junit.AfterClass
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-@LargeTest
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
abstract class PipTestBase(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = PipAppHelper(instrumentation)
- }
-
- @Test
- fun checkVisibility_pipWindowBecomesVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .hidesAppWindow(sPipWindowTitle)
- .forAllEntries()
- }
- }
-
- @Test
- fun checkVisibility_pipLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsLayer(sPipWindowTitle)
- .then()
- .hidesLayer(sPipWindowTitle)
- .forAllEntries()
- }
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = PipAppHelper(instrumentation)
companion object {
const val sPipWindowTitle = "PipMenuActivity"
-
- @AfterClass
- @JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.hasPipWindow(device)) {
- AutomationUtils.closePipWindow(device)
- }
- }
}
-}
+}
\ 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 89ffb7a..04c2f59 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
@@ -16,12 +16,22 @@
package com.android.server.wm.flicker.pip
+import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+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.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.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
@@ -37,27 +47,73 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : PipTestBase(beginRotationName, beginRotation) {
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.exitPipModeToApp(testApp as PipAppHelper, instrumentation,
- uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
- .forAllEntries()
+ 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()
+ }
+ testApp.exit()
+ }
+ }
+ transitions {
+ device.expandPipWindow()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ all("appReplacesPipWindow") {
+ this.showsAppWindow(sPipWindowTitle)
+ .then()
+ .showsAppWindowOnTop(testApp.launcherName)
+ }
+ }
+
+ 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 8591360..b6074cd 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
@@ -16,12 +16,21 @@
package com.android.server.wm.flicker.pip
+import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+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.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
@@ -37,24 +46,83 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : PipTestBase(beginRotationName, beginRotation) {
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.exitPipModeToHome(testApp as PipAppHelper, instrumentation,
- uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop("Wallpaper")
- .forAllEntries()
+ 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)
+ }
+ }
}
}
-}
+
+ 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) }
+ }
+ }
+}
\ 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 fb1cb39..5e75e4a 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,15 +16,22 @@
package com.android.server.wm.flicker.rotation
-import android.util.Log
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.WindowUtils
+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.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
@@ -44,42 +51,75 @@
beginRotation: Int,
endRotation: Int
) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice,
- beginRotation, endRotation)
- .includeJankyRuns().build()
+ 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()
+ }
- @Test
- fun checkPosition_appLayerRotates() {
- val startingPos = WindowUtils.getAppPosition(beginRotation)
- val endingPos = WindowUtils.getAppPosition(endRotation)
- Log.e(TAG, "startingPos=$startingPos endingPos=$endingPos")
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(testApp.getPackage(), startingPos).inTheBeginning()
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(testApp.getPackage(), endingPos).atTheEnd()
+ 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)
+ }
+
+ 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)
+ }
+ }
}
}
-
- @FlakyTest
- @Test
- fun checkVisibility_screenshotLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .then()
- .replaceVisibleLayer(testApp.getPackage(), SCREENSHOT_LAYER)
- .then()
- .showsLayer(testApp.getPackage()).and().showsLayer(SCREENSHOT_LAYER)
- .then()
- .replaceVisibleLayer(SCREENSHOT_LAYER, testApp.getPackage())
- .forAllEntries()
- }
- }
-}
+}
\ 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 1cd1998..de87b41 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
@@ -17,15 +17,26 @@
package com.android.server.wm.flicker.rotation
import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.Surface
-import androidx.test.InstrumentationRegistry
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.RotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+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.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
@@ -42,67 +53,101 @@
@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) {
- override val transitionToRun: TransitionRunner
- get() {
- var intentId = ""
- if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
- intentId = "BUSY_UI_THREAD"
- }
- return CommonTransitions.changeAppRotation(intent, intentId,
- InstrumentationRegistry.getContext(), instrumentation, uiDevice,
- beginRotation, endRotation).build()
+ @Test
+ fun test() {
+ var intentId = ""
+ if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
+ intentId = "BUSY_UI_THREAD"
}
- @Test
- fun checkPosition_appLayerRotates() {
- val startingPos = WindowUtils.getAppPosition(beginRotation)
- val endingPos = WindowUtils.getAppPosition(endRotation)
- if (startingPos == endingPos) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
- .forAllEntries()
+ flicker(instrumentation) {
+ withTag {
+ "changeAppRotation_" + intentId + "_" +
+ Surface.rotationToString(beginRotation) + "_" +
+ Surface.rotationToString(endRotation)
}
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
- .then()
- .hasVisibleRegion(intent.component?.packageName ?: "", endingPos)
- .forAllEntries()
+ 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)
+ }
- @Test
- fun checkCoveredRegion_noUncoveredRegions() {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
- if (startingBounds == endingBounds) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(startingBounds)
- .forAllEntries()
- }
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(startingBounds)
- .then()
- .coversRegion(endingBounds)
- .forAllEntries()
+ 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)
+ }
}
}
}
companion object {
- // launch test activity that supports seamless rotation
+ 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
@@ -110,18 +155,20 @@
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- val params: MutableCollection<Array<Any>> = ArrayList()
- val testIntents = ArrayList<Intent>()
+ val params = mutableListOf<Array<Any>>()
+ val testIntents = mutableListOf<Intent>()
// 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)
// 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) {
@@ -133,7 +180,13 @@
ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
testId += "_" + "BUSY_UI_THREAD"
}
- params.add(arrayOf(testId, testIntent, begin, end))
+ params.add(arrayOf(
+ testId,
+ testIntent,
+ Surface.rotationToString(begin),
+ Surface.rotationToString(end),
+ begin,
+ end))
}
}
}
@@ -141,4 +194,4 @@
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 b5611a4..e078f26 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,13 +16,23 @@
package com.android.server.wm.flicker.splitscreen
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+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.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.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
@@ -37,42 +47,73 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToSplitScreenTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
- beginRotation).includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
+ 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()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+
+ all("dividerLayerBecomesVisible") {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+ }
+
+ eventLog {
+ focusChanges(testApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity")
+ }
+ }
}
}
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @Test
- fun checkVisibility_dividerLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
+ 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) }
}
}
}
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 6b597e5..a08b2bf 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,24 +19,28 @@
import android.graphics.Region
import android.util.Rational
import android.view.Surface
-import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.CommonTransitions
+import androidx.test.uiautomator.By
import com.android.server.wm.flicker.FlickerTestBase
-import com.android.server.wm.flicker.LayersTrace
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.TransitionResult
-import com.android.server.wm.flicker.WindowUtils
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
+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.google.common.truth.Truth
-import org.junit.AfterClass
+import com.android.server.wm.flicker.helpers.WindowUtils
+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.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.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
@@ -53,146 +57,134 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
class ResizeSplitScreenTest : FlickerTestBase() {
- init {
- testApp = StandardAppHelper(instrumentation,
+ @Test
+ fun test() {
+ val testAppTop = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
+ val testAppBottom = ImeAppHelper(instrumentation)
- override val transitionToRun: TransitionRunner
- get() {
- val bottomApp = ImeAppHelper(instrumentation)
- return CommonTransitions.resizeSplitScreen(testApp, bottomApp, instrumentation,
- uiDevice, Surface.ROTATION_0,
- Rational(1, 3), Rational(2, 3))
- .includeJankyRuns().build()
- }
+ 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()
- @Test
- fun checkVisibility_topAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(sSimpleActivity)
- .forAllEntries()
- }
- }
+ all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sSimpleActivity)
+ }
- @Test
- fun checkVisibility_bottomAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(sImeActivity)
- .forAllEntries()
- }
- }
+ all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sImeActivity)
+ }
+ }
- @Test
- fun checkVisibility_dividerLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
- @Test
- @FlakyTest
- fun checkPosition_appsStartingBounds() {
- val displayBounds = WindowUtils.getDisplayBounds()
- checkResults { result: TransitionResult ->
- val entries = LayersTrace.parseFrom(result.layersTrace,
- result.layersTracePath, result.layersTraceChecksum)
- Truth.assertThat(entries.entries).isNotEmpty()
- val startingDividerBounds = entries.entries[0].getVisibleBounds(
- DOCKED_STACK_DIVIDER).bounds
- val startingTopAppBounds = Region(0, 0, startingDividerBounds.right,
- startingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
- val startingBottomAppBounds = Region(0,
- startingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - WindowUtils.getNavigationBarHeight())
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
- .inTheBeginning()
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
- .inTheBeginning()
- }
- }
+ all("topAppLayerIsAlwaysVisible") {
+ this.showsLayer(sSimpleActivity)
+ }
- @Test
- @FlakyTest
- fun checkPosition_appsEndingBounds() {
- val displayBounds = WindowUtils.getDisplayBounds()
- checkResults { result: TransitionResult ->
- val entries = LayersTrace.parseFrom(result.layersTrace,
- result.layersTracePath, result.layersTraceChecksum)
- Truth.assertThat(entries.entries).isNotEmpty()
- val endingDividerBounds = entries.entries[entries.entries.size - 1].getVisibleBounds(
- DOCKED_STACK_DIVIDER).bounds
- val startingTopAppBounds = Region(0, 0, endingDividerBounds.right,
- endingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
- val startingBottomAppBounds = Region(0,
- endingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - WindowUtils.getNavigationBarHeight())
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
- .atTheEnd()
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
- .atTheEnd()
- }
- }
+ all("bottomAppLayerIsAlwaysVisible") {
+ this.showsLayer(sImeActivity)
+ }
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ all("dividerLayerIsAlwaysVisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ }
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ 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
- @Test
- @FlakyTest(bugId = 156223549)
- fun checkVisibility_topAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindow(sSimpleActivity)
- .forAllEntries()
- }
- }
+ 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)
+ }
- @Test
- @FlakyTest(bugId = 156223549)
- fun checkVisibility_bottomAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindow(sImeActivity)
- .forAllEntries()
+ 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()
+ }
+ }
}
}
companion object {
private const val sSimpleActivity = "SimpleActivity"
private const val sImeActivity = "ImeActivity"
-
- @AfterClass
- @JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.isInSplitScreen(device)) {
- AutomationUtils.exitSplitScreen(device)
- }
- }
+ private val rotation = Surface.ROTATION_0
+ private val startRatio = Rational(1, 3)
+ private val stopRatio = Rational(2, 3)
}
}
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 fdcafdb..e2d7839 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
@@ -17,95 +17,112 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.InstrumentationRegistry
import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.FlickerTestBase
-import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import org.junit.AfterClass
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+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.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.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 open app to split screen.
* To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
*/
@LargeTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SplitScreenToLauncherTest : FlickerTestBase() {
- init {
- testApp = StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
+class SplitScreenToLauncherTest(
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build()
+ 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()
+ }
- @Test
- fun checkCoveredRegion_noUncoveredRegions() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(WindowUtils.getDisplayBounds()).forAllEntries()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
- @Test
- fun checkVisibility_dividerLayerBecomesInVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
- }
- }
+ // b/161435597 causes the test not to work on 90 degrees
+ all("dividerLayerBecomesInvisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ }
- @Test
- fun checkVisibility_appLayerBecomesInVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- .forAllEntries()
- }
- }
+ all("appLayerBecomesInvisible") {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ }
+ }
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
+ }
}
}
companion object {
- @AfterClass
+ @Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.isInSplitScreen(device)) {
- AutomationUtils.exitSplitScreen(device)
- }
+ fun getParams(): Collection<Array<Any>> {
+ // 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) }
}
}
}
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
new file mode 100644
index 0000000..c4bfcb1
--- /dev/null
+++ b/tests/LocalizationTest/Android.bp
@@ -0,0 +1,41 @@
+// 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.
+
+android_test {
+ name: "LocalizationTest",
+ srcs: ["java/**/*.kt"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "mockito-target-extended-minus-junit4",
+ "truth-prebuilt",
+ ],
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/tests/LocalizationTest/AndroidManifest.xml b/tests/LocalizationTest/AndroidManifest.xml
new file mode 100644
index 0000000..b135443
--- /dev/null
+++ b/tests/LocalizationTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.android.internal.app">
+
+ <application android:debuggable="true" android:testOnly="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.android.internal.app"
+ android:label="Localization Tests" />
+
+</manifest>
diff --git a/tests/LocalizationTest/AndroidTest.xml b/tests/LocalizationTest/AndroidTest.xml
new file mode 100644
index 0000000..8309b4f
--- /dev/null
+++ b/tests/LocalizationTest/AndroidTest.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.
+ -->
+<configuration description="Localization Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="LocalizationTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="LocalizationTest" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.android.internal.app" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
new file mode 100644
index 0000000..22ea971
--- /dev/null
+++ b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.android.internal.app
+
+import android.os.SystemProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.internal.R
+import com.android.internal.app.LocalePicker
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.MockitoSession
+
+@RunWith(AndroidJUnit4::class)
+class LocalizationTest {
+ private val mContext = InstrumentationRegistry.getInstrumentation().context
+ private val mUnfilteredLocales =
+ mContext.getResources().getStringArray(R.array.supported_locales)
+
+ private lateinit var mMockitoSession: MockitoSession
+
+ @Before
+ fun setUp() {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SystemProperties::class.java)
+ .startMocking()
+ }
+
+ @After
+ fun tearDown() {
+ mMockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testGetSupportedLocales_noFilter() {
+ // Filter not set.
+ setTestLocaleFilter(null)
+
+ val locales1 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales1).isEqualTo(mUnfilteredLocales)
+
+ // Empty filter.
+ setTestLocaleFilter("")
+
+ val locales2 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales2).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_invalidFilter() {
+ setTestLocaleFilter("**")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_inclusiveFilter() {
+ setTestLocaleFilter("^(de-AT|de-DE|en|ru).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { it.startsWithAnyOf("de-AT", "de-DE", "en", "ru") }
+ .toTypedArray()
+ )
+ }
+
+ @Test
+ fun testGetSupportedLocales_exclusiveFilter() {
+ setTestLocaleFilter("^(?!de-IT|es|fr).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { !it.startsWithAnyOf("de-IT", "es", "fr") }
+ .toTypedArray()
+ )
+ }
+
+ private fun setTestLocaleFilter(localeFilter: String?) {
+ doReturn(localeFilter).`when` { SystemProperties.get(eq("ro.localization.locale_filter")) }
+ }
+
+ private fun String.startsWithAnyOf(vararg prefixes: String): Boolean {
+ prefixes.forEach {
+ if (startsWith(it)) return true
+ }
+
+ return false
+ }
+}
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index b7c47c2..dd3f5be 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -19,23 +19,23 @@
import android.app.Instrumentation
import android.content.Context
import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
+import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
+import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
import android.os.Build
import android.os.HandlerThread
import android.os.Looper
-import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
import androidx.test.InstrumentationRegistry
-import com.android.testutils.ArrayTrackRecord
+import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
-import java.util.UUID
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import java.util.UUID
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
private const val DEFAULT_TIMEOUT_MS = 5000L
private val instrumentation: Instrumentation
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1e7fecf..0f24b0c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4226,7 +4226,7 @@
callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
}
- // Sanity check before testing started keepalive.
+ // Basic check before testing started keepalive.
try (SocketKeepalive ka = mCm.createSocketKeepalive(
myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
ka.start(validKaInterval);
diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/net/java/com/android/server/NetIdManagerTest.kt
index 045f89f..6f5e740 100644
--- a/tests/net/java/com/android/server/NetIdManagerTest.kt
+++ b/tests/net/java/com/android/server/NetIdManagerTest.kt
@@ -19,8 +19,8 @@
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.NetIdManager.MIN_NET_ID
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
import com.android.testutils.assertThrows
+import com.android.testutils.ExceptionUtils.ThrowingRunnable
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c..a384687 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -26,10 +26,9 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
@@ -97,7 +96,6 @@
private static final int SYSTEM_UID1 = 1000;
private static final int SYSTEM_UID2 = 1008;
private static final int VPN_UID = 10002;
- private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
@@ -128,6 +126,7 @@
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
}));
+ doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), anyInt());
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -140,35 +139,15 @@
verify(mMockPmi).getPackageList(mPermissionMonitor);
}
- private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
- String... permissions) {
- final PackageInfo packageInfo =
- packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
+ private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
+ final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- packageInfo.applicationInfo.uid = uid;
- return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
+ return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
}
- private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- }
-
- private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
- }
-
- private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
- String[] permissions, String partition) {
- int[] requestedPermissionsFlags = new int[permissions.length];
- for (int i = 0; i < permissions.length; i++) {
- requestedPermissionsFlags[i] = permissionsFlags;
- }
+ private static PackageInfo packageInfoWithPartition(String partition) {
final PackageInfo packageInfo = new PackageInfo();
- packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -185,168 +164,145 @@
return packageInfo;
}
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
- final PackageInfo pkgInfo;
- if (hasSystemPermission) {
- pkgInfo = systemPackageInfoWithPermissions(
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- } else {
- pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
- }
+ private static PackageInfo buildPackageInfo(String partition, int uid, int userId) {
+ final PackageInfo pkgInfo = packageInfoWithPartition(partition);
pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
return pkgInfo;
}
+ /** This will REMOVE all previously set permissions from given uid. */
+ private void removeAllPermissions(int uid) {
+ doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), eq(uid));
+ }
+
+ /** Set up mocks so that given UID has the requested permissions. */
+ private void addPermissions(int uid, String... permissions) {
+ for (String permission : permissions) {
+ doReturn(PackageManager.PERMISSION_GRANTED)
+ .when(mDeps).uidPermission(eq(permission), eq(uid));
+ }
+ }
+
@Test
public void testHasPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+ addPermissions(MOCK_UID1);
+ assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
+ addPermissions(MOCK_UID1, CHANGE_NETWORK_STATE, NETWORK_STACK);
+ assertTrue(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
+ assertTrue(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID2));
+ assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID2));
- app = systemPackageInfoWithPermissions(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
- PARTITION_SYSTEM);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissions = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissionsFlags = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ addPermissions(MOCK_UID2, CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+ assertTrue(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID2));
+ assertTrue(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID2));
}
@Test
public void testIsVendorApp() {
- PackageInfo app = systemPackageInfoWithPermissions();
+ PackageInfo app = packageInfoWithPartition(PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_OEM);
+ app = packageInfoWithPartition(PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_PRODUCT);
+ app = packageInfoWithPartition(PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = vendorPackageInfoWithPermissions();
+ app = packageInfoWithPartition(PARTITION_VENDOR);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
- @Test
- public void testHasNetworkPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- assertTrue(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ /**
+ * Remove all permissions from the uid then setup permissions to uid for checking restricted
+ * network permission.
+ */
+ private void assertRestrictedNetworkPermission(boolean hasPermission, int uid,
+ String... permissions) {
+ removeAllPermissions(uid);
+ addPermissions(uid, permissions);
+ assertEquals(hasPermission, mPermissionMonitor.hasRestrictedNetworkPermission(uid));
}
@Test
public void testHasRestrictedNetworkPermission() {
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
+ assertRestrictedNetworkPermission(false, MOCK_UID1);
+ assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_NETWORK_STATE);
+ assertRestrictedNetworkPermission(true, MOCK_UID1, NETWORK_STACK);
+ assertRestrictedNetworkPermission(false, MOCK_UID1, CONNECTIVITY_INTERNAL);
+ assertRestrictedNetworkPermission(true, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertRestrictedNetworkPermission(false, MOCK_UID1, CHANGE_WIFI_STATE);
+ assertRestrictedNetworkPermission(true, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK);
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(MOCK_UID2));
+ assertFalse(mPermissionMonitor.hasRestrictedNetworkPermission(SYSTEM_UID));
}
@Test
- public void testHasRestrictedNetworkPermissionSystemUid() {
+ public void testIsCarryoverPackage() {
doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+ assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
- @Test
- public void testHasRestrictedNetworkPermissionVendorApp() {
- assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
- assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
+ assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
}
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
String... permissions) throws Exception {
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
+ .thenReturn(buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1));
+ addPermissions(uid, permissions);
mPermissionMonitor.onPackageAdded(name, uid);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
}
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
-
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
- assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertBackgroundPermission(false, "mock1", MOCK_UID1);
+ assertBackgroundPermission(false, "mock2", MOCK_UID1, CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, "mock3", MOCK_UID1, NETWORK_STACK);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
- CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
+ assertBackgroundPermission(false, "mock4", MOCK_UID2);
+ assertBackgroundPermission(true, "mock5", MOCK_UID2,
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+
+ doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
+ assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
+ assertBackgroundPermission(false, "system1", SYSTEM_UID);
+ assertBackgroundPermission(true, "system2", SYSTEM_UID, CHANGE_NETWORK_STATE);
+ doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
+ removeAllPermissions(SYSTEM_UID);
+ assertBackgroundPermission(true, "system3", SYSTEM_UID);
}
private class NetdMonitor {
@@ -416,13 +372,14 @@
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
// SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM),
+ anyString(), anyInt());
doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1));
+ eq(SYSTEM_PACKAGE1), anyInt());
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2));
+ eq(SYSTEM_PACKAGE2), anyInt());
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1));
+ eq(MOCK_PACKAGE1), anyInt());
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
@@ -473,13 +430,15 @@
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
+ buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID2, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
+ addPermissions(SYSTEM_UID,
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -524,11 +483,11 @@
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false, VPN_UID, MOCK_USER1)
+ buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
@@ -633,10 +592,10 @@
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
+ final PackageInfo packageInfo = buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
+ addPermissions(uid, permissions);
return packageInfo;
}
@@ -663,14 +622,13 @@
public void testPackageInstallSharedUid() throws Exception {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
- new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
+ final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
@@ -701,6 +659,7 @@
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ removeAllPermissions(MOCK_UID1);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
@@ -728,10 +687,12 @@
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
+ final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});
+ removeAllPermissions(MOCK_UID1);
+ addPermissions(MOCK_UID1, INTERNET);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
@@ -743,9 +704,6 @@
// necessary permission.
final Context realContext = InstrumentationRegistry.getContext();
final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- final PackageManager manager = realContext.getPackageManager();
- final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
- GET_PERMISSIONS | MATCH_ANY_USER);
- assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(monitor.hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, SYSTEM_UID));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 551498f..e83d2a9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -23,11 +23,12 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static com.android.server.net.NetworkStatsCollection.multiplySafe;
+import static com.android.testutils.MiscAssertsKt.assertThrows;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -505,23 +506,25 @@
}
@Test
- public void testMultiplySafe() {
- assertEquals(25, multiplySafe(50, 1, 2));
- assertEquals(100, multiplySafe(50, 2, 1));
+ public void testMultiplySafeRational() {
+ assertEquals(25, multiplySafeByRational(50, 1, 2));
+ assertEquals(100, multiplySafeByRational(50, 2, 1));
- assertEquals(-10, multiplySafe(30, -1, 3));
- assertEquals(0, multiplySafe(30, 0, 3));
- assertEquals(10, multiplySafe(30, 1, 3));
- assertEquals(20, multiplySafe(30, 2, 3));
- assertEquals(30, multiplySafe(30, 3, 3));
- assertEquals(40, multiplySafe(30, 4, 3));
+ assertEquals(-10, multiplySafeByRational(30, -1, 3));
+ assertEquals(0, multiplySafeByRational(30, 0, 3));
+ assertEquals(10, multiplySafeByRational(30, 1, 3));
+ assertEquals(20, multiplySafeByRational(30, 2, 3));
+ assertEquals(30, multiplySafeByRational(30, 3, 3));
+ assertEquals(40, multiplySafeByRational(30, 4, 3));
assertEquals(100_000_000_000L,
- multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
+ multiplySafeByRational(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
assertEquals(100_000_000_010L,
- multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
+ multiplySafeByRational(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
assertEquals(823_202_048L,
- multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
+ multiplySafeByRational(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
+
+ assertThrows(ArithmeticException.class, () -> multiplySafeByRational(30, 3, 0));
}
/**
diff --git a/tests/utils/DummyIME/Android.bp b/tests/utils/StubIME/Android.bp
similarity index 96%
rename from tests/utils/DummyIME/Android.bp
rename to tests/utils/StubIME/Android.bp
index 4a44b3b..668c92c 100644
--- a/tests/utils/DummyIME/Android.bp
+++ b/tests/utils/StubIME/Android.bp
@@ -15,7 +15,7 @@
//
android_test {
- name: "DummyIME",
+ name: "StubIME",
srcs: ["src/**/*.java"],
sdk_version: "current",
}
diff --git a/tests/utils/DummyIME/AndroidManifest.xml b/tests/utils/StubIME/AndroidManifest.xml
similarity index 80%
rename from tests/utils/DummyIME/AndroidManifest.xml
rename to tests/utils/StubIME/AndroidManifest.xml
index 4dc0b57..bc64c67 100644
--- a/tests/utils/DummyIME/AndroidManifest.xml
+++ b/tests/utils/StubIME/AndroidManifest.xml
@@ -18,20 +18,20 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.testing.dummyime">
+ package="com.android.testing.stubime">
<application android:label="Dummy IME">
<service android:name="DummyIme"
- android:permission="android.permission.BIND_INPUT_METHOD"
- android:exported="true">
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
<meta-data android:name="android.view.im"
- android:resource="@xml/method"/>
+ android:resource="@xml/method"/>
</service>
<activity android:name=".ImePreferences"
- android:label="Dummy IME Settings"
- android:exported="true">
+ android:label="Stub IME Settings"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
diff --git a/tests/utils/DummyIME/res/xml/method.xml b/tests/utils/StubIME/res/xml/method.xml
similarity index 92%
rename from tests/utils/DummyIME/res/xml/method.xml
rename to tests/utils/StubIME/res/xml/method.xml
index 43a330e..1bb4bcd 100644
--- a/tests/utils/DummyIME/res/xml/method.xml
+++ b/tests/utils/StubIME/res/xml/method.xml
@@ -21,9 +21,9 @@
<!-- for the Search Manager. -->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.android.testing.dummyime.ImePreferences">
+ android:settingsActivity="com.android.testing.stubime.ImePreferences">
<subtype
android:label="Generic"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard" />
-</input-method>
\ No newline at end of file
+</input-method>
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
similarity index 90%
rename from tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
rename to tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
index 41036ab..b77525a 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.preference.PreferenceActivity;
/**
- * Dummy IME preference activity
+ * Stub IME preference activity
*/
public class ImePreferences extends PreferenceActivity {
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
similarity index 85%
rename from tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
rename to tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
index 7b7a39a..8795202 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.inputmethodservice.InputMethodService;
/**
- * Dummy IME implementation that basically does nothing
+ * Stub IME implementation that basically does nothing
*/
-public class DummyIme extends InputMethodService {
+public class StubIme extends InputMethodService {
@Override
public boolean onEvaluateFullscreenMode() {
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 931a14b..3d9be59 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -342,7 +342,7 @@
}
}
- // Sanity check to make sure we processed all the nodes.
+ // Validity check to make sure we processed all the nodes.
CHECK(node_stack.size() == 1u);
CHECK(node_stack.back() == &root);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 469128b..7dfc983 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -740,7 +740,7 @@
if (type == ResourceType::kId) {
if (res_value.dataType != android::Res_value::TYPE_REFERENCE &&
res_value.dataType != android::Res_value::TYPE_DYNAMIC_REFERENCE) {
- // plain "id" resources are actually encoded as dummy values (aapt1 uses an empty string,
+ // plain "id" resources are actually encoded as unused values (aapt1 uses an empty string,
// while aapt2 uses a false boolean).
return util::make_unique<Id>();
}
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index ab9ce66..b1e1a77 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -168,6 +168,7 @@
ODM = 6;
OEM = 7;
ACTOR = 8;
+ CONFIG_SIGNATURE = 9;
}
// The location of the <item> declaration in source.
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index fb7f6d7..f9c54f6 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1401,7 +1401,7 @@
return MergeExportedSymbols(compiled_file.source, compiled_file.exported_symbols);
}
- // Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+ // Takes a path to load as a ZIP file and merges the files within into the main ResourceTable.
// If override is true, conflicting resources are allowed to override each other, in order of last
// seen.
// An io::IFileCollection is created from the ZIP file and added to the set of
@@ -1432,7 +1432,7 @@
return !error;
}
- // Takes a path to load and merge into the master ResourceTable. If override is true,
+ // Takes a path to load and merge into the main ResourceTable. If override is true,
// conflicting resources are allowed to override each other, in order of last seen.
// If the file path ends with .flata, .jar, .jack, or .zip the file is treated
// as ZIP archive and the files within are merged individually.
@@ -1449,7 +1449,7 @@
return MergeFile(file, override);
}
- // Takes an AAPT Container file (.apc/.flat) to load and merge into the master ResourceTable.
+ // Takes an AAPT Container file (.apc/.flat) to load and merge into the main ResourceTable.
// If override is true, conflicting resources are allowed to override each other, in order of last
// seen.
// All other file types are ignored. This is because these files could be coming from a zip,
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index e36668e..5b18a37 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -132,8 +132,8 @@
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "Optimizing APK...");
}
- if (!options_.resources_blacklist.empty()) {
- ResourceFilter filter(options_.resources_blacklist);
+ if (!options_.resources_exclude_list.empty()) {
+ ResourceFilter filter(options_.resources_exclude_list);
if (!filter.Consume(context_, apk->GetResourceTable())) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed filtering resources");
return 1;
@@ -328,7 +328,7 @@
}
for (StringPiece directive : util::Tokenize(directives, ',')) {
if (directive == "remove") {
- options->resources_blacklist.insert(resource_name.ToResourceName());
+ options->resources_exclude_list.insert(resource_name.ToResourceName());
} else if (directive == "no_collapse" || directive == "no_obfuscate") {
options->table_flattener_options.name_collapse_exemptions.insert(
resource_name.ToResourceName());
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 5070ccc..3afc46b 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -36,8 +36,8 @@
// Details of the app extracted from the AndroidManifest.xml
AppInfo app_info;
- // Blacklist of unused resources that should be removed from the apk.
- std::unordered_set<ResourceName> resources_blacklist;
+ // Exclude list of unused resources that should be removed from the apk.
+ std::unordered_set<ResourceName> resources_exclude_list;
// Split APK options.
TableSplitterOptions table_splitter_options;
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index bc2e699..4db2392 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -35,7 +35,7 @@
((uint32_t)d);
}
-// Whitelist of PNG chunk types that we want to keep in the resulting PNG.
+// Allow list of PNG chunk types that we want to keep in the resulting PNG.
enum PngChunkTypes {
kPngChunkIHDR = u32(73, 72, 68, 82),
kPngChunkIDAT = u32(73, 68, 65, 84),
@@ -56,7 +56,7 @@
return word;
}
-static bool IsPngChunkWhitelisted(uint32_t type) {
+static bool IsPngChunkAllowed(uint32_t type) {
switch (type) {
case kPngChunkIHDR:
case kPngChunkIDAT:
@@ -128,7 +128,7 @@
// Do we strip this chunk?
const uint32_t chunk_type = Peek32LE(data_.data() + window_end_ + sizeof(uint32_t));
- if (IsPngChunkWhitelisted(chunk_type)) {
+ if (IsPngChunkAllowed(chunk_type)) {
// Advance the window to include this chunk.
window_end_ += kMinChunkHeaderSize + chunk_len;
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 2ef8b99..e5b3107 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -187,7 +187,7 @@
TEST_F(ConfigurationParserTest, ExtractConfiguration) {
Maybe<PostProcessingConfiguration> maybe_config =
- ExtractConfiguration(kValidConfig, "dummy.xml", &diag_);
+ ExtractConfiguration(kValidConfig, "fake.xml", &diag_);
PostProcessingConfiguration config = maybe_config.value();
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 53d9ffe..71c70da 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -188,7 +188,7 @@
/** Retrieves the resource assigned to the specified resource id if one exists. */
Value* FindValueById(const ResourceTable* table, const ResourceId& res_id,
- const ConfigDescription& config = DummyConfig()) {
+ const ConfigDescription& config = DefaultConfig()) {
if (table) {
for (auto& package : table->packages) {
if (package->id && package->id.value() == res_id.package_id()) {
@@ -210,7 +210,7 @@
}
/** Attempts to resolve the reference to a non-reference value. */
- Value* ResolveReference(Reference* ref, const ConfigDescription& config = DummyConfig()) {
+ Value* ResolveReference(Reference* ref, const ConfigDescription& config = DefaultConfig()) {
const int kMaxIterations = 40;
int i = 0;
while (ref && ref->id && i++ < kMaxIterations) {
@@ -231,10 +231,10 @@
* this will attempt to resolve the reference to an integer value.
**/
int32_t* GetAttributeInteger(xml::Attribute* attr,
- const ConfigDescription& config = DummyConfig()) {
+ const ConfigDescription& config = DefaultConfig()) {
if (attr != nullptr) {
if (attr->compiled_value) {
- // Resolve references using the dummy configuration
+ // Resolve references using the configuration
Value* value = attr->compiled_value.get();
if (ValueCast<Reference>(value)) {
value = ResolveReference(ValueCast<Reference>(value), config);
@@ -257,7 +257,7 @@
* exist or cannot be resolved to an integer value.
**/
int32_t GetAttributeIntegerDefault(xml::Attribute* attr, int32_t def,
- const ConfigDescription& config = DummyConfig()) {
+ const ConfigDescription& config = DefaultConfig()) {
auto value = GetAttributeInteger(attr, config);
if (value) {
return *value;
@@ -270,10 +270,10 @@
* this will attempt to resolve the reference to a string value.
**/
const std::string* GetAttributeString(xml::Attribute* attr,
- const ConfigDescription& config = DummyConfig()) {
+ const ConfigDescription& config = DefaultConfig()) {
if (attr != nullptr) {
if (attr->compiled_value) {
- // Resolve references using the dummy configuration
+ // Resolve references using the configuration
Value* value = attr->compiled_value.get();
if (ValueCast<Reference>(value)) {
value = ResolveReference(ValueCast<Reference>(value), config);
@@ -305,7 +305,7 @@
* exist or cannot be resolved to an string value.
**/
std::string GetAttributeStringDefault(xml::Attribute* attr, std::string def,
- const ConfigDescription& config = DummyConfig()) {
+ const ConfigDescription& config = DefaultConfig()) {
auto value = GetAttributeString(attr, config);
if (value) {
return *value;
@@ -322,7 +322,7 @@
friend Element;
/** Creates a default configuration used to retrieve resources. */
- static ConfigDescription DummyConfig() {
+ static ConfigDescription DefaultConfig() {
ConfigDescription config;
config.orientation = android::ResTable_config::ORIENTATION_PORT;
config.density = android::ResTable_config::DENSITY_MEDIUM;
@@ -1871,7 +1871,7 @@
// Collect all the unique locales of the apk
if (locales_.find(locale_str) == locales_.end()) {
- ConfigDescription config = ManifestExtractor::DummyConfig();
+ ConfigDescription config = ManifestExtractor::DefaultConfig();
config.setBcp47Locale(locale_str.data());
locales_.insert(std::make_pair(locale_str, config));
}
@@ -1880,7 +1880,7 @@
uint16_t density = (value->config.density == 0) ? (uint16_t) 160
: value->config.density;
if (densities_.find(density) == densities_.end()) {
- ConfigDescription config = ManifestExtractor::DummyConfig();
+ ConfigDescription config = ManifestExtractor::DefaultConfig();
config.density = density;
densities_.insert(std::make_pair(density, config));
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 59627ce..6932baf 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -776,6 +776,7 @@
OverlayableItem overlayable_item_three(group_one);
overlayable_item_three.policies |= PolicyFlags::SIGNATURE;
overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE;
+ overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE;
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
@@ -830,7 +831,8 @@
EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE
- | PolicyFlags::ACTOR_SIGNATURE);
+ | PolicyFlags::ACTOR_SIGNATURE
+ | PolicyFlags::CONFIG_SIGNATURE);
}
TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 582bd39..06ac9e5 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -404,6 +404,9 @@
case pb::OverlayableItem::ACTOR:
out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE;
break;
+ case pb::OverlayableItem::CONFIG_SIGNATURE:
+ out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE;
+ break;
default:
*out_error = "unknown overlayable policy";
return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 5ab43b7..98c5175 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -325,6 +325,9 @@
if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR);
}
+ if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) {
+ pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE);
+ }
if (source_pool != nullptr) {
SerializeSourceToPb(overlayable_item.source, source_pool,
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
index ba9646f..ec3c543 100644
--- a/tools/aapt2/jni/aapt2_jni.cpp
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -139,5 +139,5 @@
JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping(
JNIEnv *env, jclass aapt_obj) {
- // This is just a dummy method to see if the library has been loaded.
+ // This is just a no-op method to see if the library has been loaded.
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 49f8e1b..dac21d7 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -570,8 +570,8 @@
}
xml::XmlActionExecutorPolicy policy = options_.warn_validation
- ? xml::XmlActionExecutorPolicy::kWhitelistWarning
- : xml::XmlActionExecutorPolicy::kWhitelist;
+ ? xml::XmlActionExecutorPolicy::kAllowListWarning
+ : xml::XmlActionExecutorPolicy::kAllowList;
if (!executor.Execute(policy, context->GetDiagnostics(), doc)) {
return false;
}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index c25e450..ad56092 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -31,11 +31,11 @@
TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
const TableMergerOptions& options)
- : context_(context), master_table_(out_table), options_(options) {
+ : context_(context), main_table_(out_table), options_(options) {
// Create the desired package that all tables will be merged into.
- master_package_ =
- master_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId());
- CHECK(master_package_ != nullptr) << "package name or ID already taken";
+ main_package_ =
+ main_table_->CreatePackage(context_->GetCompilationPackage(), context_->GetPackageId());
+ CHECK(main_package_ != nullptr) << "package name or ID already taken";
}
bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
@@ -235,7 +235,7 @@
bool error = false;
for (auto& src_type : src_package->types) {
- ResourceTableType* dst_type = master_package_->FindOrCreateType(src_type->type);
+ ResourceTableType* dst_type = main_package_->FindOrCreateType(src_type->type);
if (!MergeType(context_, src, dst_type, src_type.get())) {
error = true;
continue;
@@ -279,7 +279,7 @@
if (dst_config_value) {
CollisionResult collision_result = MergeConfigValue(
context_, res_name, overlay, options_.override_styles_instead_of_overlaying,
- dst_config_value, src_config_value.get(), &master_table_->string_pool);
+ dst_config_value, src_config_value.get(), &main_table_->string_pool);
if (collision_result == CollisionResult::kConflict) {
error = true;
continue;
@@ -298,7 +298,7 @@
if (mangle_package) {
new_file_ref = CloneAndMangleFile(src_package->name, *f);
} else {
- new_file_ref = std::unique_ptr<FileReference>(f->Clone(&master_table_->string_pool));
+ new_file_ref = std::unique_ptr<FileReference>(f->Clone(&main_table_->string_pool));
}
dst_config_value->value = std::move(new_file_ref);
@@ -307,7 +307,7 @@
? dst_config_value->value->GetComment() : Maybe<std::string>();
dst_config_value->value = std::unique_ptr<Value>(
- src_config_value->value->Clone(&master_table_->string_pool));
+ src_config_value->value->Clone(&main_table_->string_pool));
// Keep the comment from the original resource and ignore all comments from overlaying
// resources
@@ -328,14 +328,14 @@
std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string());
std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string();
std::unique_ptr<FileReference> new_file_ref =
- util::make_unique<FileReference>(master_table_->string_pool.MakeRef(newPath));
+ util::make_unique<FileReference>(main_table_->string_pool.MakeRef(newPath));
new_file_ref->SetComment(file_ref.GetComment());
new_file_ref->SetSource(file_ref.GetSource());
new_file_ref->type = file_ref.type;
new_file_ref->file = file_ref.file;
return new_file_ref;
}
- return std::unique_ptr<FileReference>(file_ref.Clone(&master_table_->string_pool));
+ return std::unique_ptr<FileReference>(file_ref.Clone(&main_table_->string_pool));
}
bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFile* file) {
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index a35a134..e01a0c1 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -80,9 +80,9 @@
DISALLOW_COPY_AND_ASSIGN(TableMerger);
IAaptContext* context_;
- ResourceTable* master_table_;
+ ResourceTable* main_table_;
TableMergerOptions options_;
- ResourceTablePackage* master_package_;
+ ResourceTablePackage* main_package_;
std::set<std::string> merged_packages_;
bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
diff --git a/tools/aapt2/link/XmlCompatVersioner.cpp b/tools/aapt2/link/XmlCompatVersioner.cpp
index 20ebdc6..6937ca9 100644
--- a/tools/aapt2/link/XmlCompatVersioner.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner.cpp
@@ -143,8 +143,8 @@
// Iterate from smallest to largest API version.
for (ApiVersion api : apis_referenced) {
- std::set<ApiVersion> dummy;
- versioned_docs.push_back(ProcessDoc(api, api_range.end, doc, &dummy));
+ std::set<ApiVersion> tmp;
+ versioned_docs.push_back(ProcessDoc(api, api_range.end, doc, &tmp));
}
return versioned_docs;
}
diff --git a/tools/aapt2/optimize/ResourceFilter.cpp b/tools/aapt2/optimize/ResourceFilter.cpp
index 250b651..08c045b 100644
--- a/tools/aapt2/optimize/ResourceFilter.cpp
+++ b/tools/aapt2/optimize/ResourceFilter.cpp
@@ -20,8 +20,8 @@
namespace aapt {
-ResourceFilter::ResourceFilter(const std::unordered_set<ResourceName>& blacklist)
- : blacklist_(blacklist) {
+ResourceFilter::ResourceFilter(const std::unordered_set<ResourceName>& exclude_list)
+ : exclude_list_(exclude_list) {
}
bool ResourceFilter::Consume(IAaptContext* context, ResourceTable* table) {
@@ -29,7 +29,7 @@
for (auto& type : package->types) {
for (auto it = type->entries.begin(); it != type->entries.end(); ) {
ResourceName resource = ResourceName({}, type->type, (*it)->name);
- if (blacklist_.find(resource) != blacklist_.end()) {
+ if (exclude_list_.find(resource) != exclude_list_.end()) {
it = type->entries.erase(it);
} else {
++it;
diff --git a/tools/aapt2/optimize/ResourceFilter.h b/tools/aapt2/optimize/ResourceFilter.h
index d4baf65..a264533 100644
--- a/tools/aapt2/optimize/ResourceFilter.h
+++ b/tools/aapt2/optimize/ResourceFilter.h
@@ -25,16 +25,16 @@
namespace aapt {
-// Removes non-whitelisted entries from resource table.
+// Removes exclude-listed entries from resource table.
class ResourceFilter : public IResourceTableConsumer {
public:
- explicit ResourceFilter(const std::unordered_set<ResourceName>& blacklist);
+ explicit ResourceFilter(const std::unordered_set<ResourceName>& exclude_list);
bool Consume(IAaptContext* context, ResourceTable* table) override;
private:
DISALLOW_COPY_AND_ASSIGN(ResourceFilter);
- std::unordered_set<ResourceName> blacklist_;
+ std::unordered_set<ResourceName> exclude_list_;
};
} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourceFilter_test.cpp b/tools/aapt2/optimize/ResourceFilter_test.cpp
index ef57f9c..34d8fd2 100644
--- a/tools/aapt2/optimize/ResourceFilter_test.cpp
+++ b/tools/aapt2/optimize/ResourceFilter_test.cpp
@@ -31,22 +31,22 @@
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
- .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
- .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
- .AddString("android:string/notblacklisted2", ResourceId{}, default_config, "value")
- .AddString("android:string/blacklisted2", ResourceId{}, default_config, "value")
+ .AddString("android:string/notexclude_listed", ResourceId{}, default_config, "value")
+ .AddString("android:string/exclude_listed", ResourceId{}, default_config, "value")
+ .AddString("android:string/notexclude_listed2", ResourceId{}, default_config, "value")
+ .AddString("android:string/exclude_listed2", ResourceId{}, default_config, "value")
.Build();
- std::unordered_set<ResourceName> blacklist = {
- ResourceName({}, ResourceType::kString, "blacklisted"),
- ResourceName({}, ResourceType::kString, "blacklisted2"),
+ std::unordered_set<ResourceName> exclude_list = {
+ ResourceName({}, ResourceType::kString, "exclude_listed"),
+ ResourceName({}, ResourceType::kString, "exclude_listed2"),
};
- ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
- EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
- EXPECT_THAT(table, HasValue("android:string/notblacklisted2", default_config));
- EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
- EXPECT_THAT(table, Not(HasValue("android:string/blacklisted2", default_config)));
+ ASSERT_TRUE(ResourceFilter(exclude_list).Consume(context.get(), table.get()));
+ EXPECT_THAT(table, HasValue("android:string/notexclude_listed", default_config));
+ EXPECT_THAT(table, HasValue("android:string/notexclude_listed2", default_config));
+ EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed", default_config)));
+ EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed2", default_config)));
}
TEST(ResourceFilterTest, TypeIsCheckedBeforeFiltering) {
@@ -55,21 +55,21 @@
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
- .AddString("android:string/notblacklisted", ResourceId{}, default_config, "value")
- .AddString("android:string/blacklisted", ResourceId{}, default_config, "value")
- .AddString("android:drawable/notblacklisted", ResourceId{}, default_config, "value")
- .AddString("android:drawable/blacklisted", ResourceId{}, default_config, "value")
+ .AddString("android:string/notexclude_listed", ResourceId{}, default_config, "value")
+ .AddString("android:string/exclude_listed", ResourceId{}, default_config, "value")
+ .AddString("android:drawable/notexclude_listed", ResourceId{}, default_config, "value")
+ .AddString("android:drawable/exclude_listed", ResourceId{}, default_config, "value")
.Build();
- std::unordered_set<ResourceName> blacklist = {
- ResourceName({}, ResourceType::kString, "blacklisted"),
+ std::unordered_set<ResourceName> exclude_list = {
+ ResourceName({}, ResourceType::kString, "exclude_listed"),
};
- ASSERT_TRUE(ResourceFilter(blacklist).Consume(context.get(), table.get()));
- EXPECT_THAT(table, HasValue("android:string/notblacklisted", default_config));
- EXPECT_THAT(table, HasValue("android:drawable/blacklisted", default_config));
- EXPECT_THAT(table, HasValue("android:drawable/notblacklisted", default_config));
- EXPECT_THAT(table, Not(HasValue("android:string/blacklisted", default_config)));
+ ASSERT_TRUE(ResourceFilter(exclude_list).Consume(context.get(), table.get()));
+ EXPECT_THAT(table, HasValue("android:string/notexclude_listed", default_config));
+ EXPECT_THAT(table, HasValue("android:drawable/exclude_listed", default_config));
+ EXPECT_THAT(table, HasValue("android:drawable/notexclude_listed", default_config));
+ EXPECT_THAT(table, Not(HasValue("android:string/exclude_listed", default_config)));
}
} // namespace aapt
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index b54c155..23c2218 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -21,7 +21,7 @@
namespace aapt {
namespace test {
-struct DummyDiagnosticsImpl : public IDiagnostics {
+struct TestDiagnosticsImpl : public IDiagnostics {
void Log(Level level, DiagMessageActual& actual_msg) override {
switch (level) {
case Level::Note:
@@ -39,7 +39,7 @@
};
IDiagnostics* GetDiagnostics() {
- static DummyDiagnosticsImpl diag;
+ static TestDiagnosticsImpl diag;
return &diag;
}
diff --git a/tools/aapt2/trace/TraceBuffer.h b/tools/aapt2/trace/TraceBuffer.h
index 8618e0e..ba751dd 100644
--- a/tools/aapt2/trace/TraceBuffer.h
+++ b/tools/aapt2/trace/TraceBuffer.h
@@ -40,7 +40,7 @@
void BeginTrace(const std::string& tag);
void EndTrace();
-// A master trace is required to flush events to disk. Events are formatted in systrace
+// A main trace is required to flush events to disk. Events are formatted in systrace
// json format.
class FlushTrace {
public:
diff --git a/tools/aapt2/util/Maybe_test.cpp b/tools/aapt2/util/Maybe_test.cpp
index 2057ddc..4c921f1 100644
--- a/tools/aapt2/util/Maybe_test.cpp
+++ b/tools/aapt2/util/Maybe_test.cpp
@@ -22,32 +22,32 @@
namespace aapt {
-struct Dummy {
- Dummy() {
+struct Fake {
+ Fake() {
data = new int;
*data = 1;
- std::cerr << "Construct Dummy{0x" << (void*)this << "} with data=0x"
+ std::cerr << "Construct Fake{0x" << (void*)this << "} with data=0x"
<< (void*)data << std::endl;
}
- Dummy(const Dummy& rhs) {
+ Fake(const Fake& rhs) {
data = nullptr;
if (rhs.data) {
data = new int;
*data = *rhs.data;
}
- std::cerr << "CopyConstruct Dummy{0x" << (void*)this << "} from Dummy{0x"
+ std::cerr << "CopyConstruct Fake{0x" << (void*)this << "} from Fake{0x"
<< (const void*)&rhs << "}" << std::endl;
}
- Dummy(Dummy&& rhs) {
+ Fake(Fake&& rhs) {
data = rhs.data;
rhs.data = nullptr;
- std::cerr << "MoveConstruct Dummy{0x" << (void*)this << "} from Dummy{0x"
+ std::cerr << "MoveConstruct Fake{0x" << (void*)this << "} from Fake{0x"
<< (const void*)&rhs << "}" << std::endl;
}
- Dummy& operator=(const Dummy& rhs) {
+ Fake& operator=(const Fake& rhs) {
delete data;
data = nullptr;
@@ -55,22 +55,22 @@
data = new int;
*data = *rhs.data;
}
- std::cerr << "CopyAssign Dummy{0x" << (void*)this << "} from Dummy{0x"
+ std::cerr << "CopyAssign Fake{0x" << (void*)this << "} from Fake{0x"
<< (const void*)&rhs << "}" << std::endl;
return *this;
}
- Dummy& operator=(Dummy&& rhs) {
+ Fake& operator=(Fake&& rhs) {
delete data;
data = rhs.data;
rhs.data = nullptr;
- std::cerr << "MoveAssign Dummy{0x" << (void*)this << "} from Dummy{0x"
+ std::cerr << "MoveAssign Fake{0x" << (void*)this << "} from Fake{0x"
<< (const void*)&rhs << "}" << std::endl;
return *this;
}
- ~Dummy() {
- std::cerr << "Destruct Dummy{0x" << (void*)this << "} with data=0x"
+ ~Fake() {
+ std::cerr << "Destruct Fake{0x" << (void*)this << "} with data=0x"
<< (void*)data << std::endl;
delete data;
}
@@ -100,15 +100,15 @@
}
TEST(MaybeTest, Lifecycle) {
- Maybe<Dummy> val = make_nothing<Dummy>();
+ Maybe<Fake> val = make_nothing<Fake>();
- Maybe<Dummy> val2 = make_value(Dummy());
+ Maybe<Fake> val2 = make_value(Fake());
}
TEST(MaybeTest, MoveAssign) {
- Maybe<Dummy> val;
+ Maybe<Fake> val;
{
- Maybe<Dummy> val2 = Dummy();
+ Maybe<Fake> val2 = Fake();
val = std::move(val2);
}
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index cb844f0..fab17c9 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -74,11 +74,11 @@
for (const StringPiece& element : *bread_crumb) {
error_msg << "<" << element << ">";
}
- if (policy == XmlActionExecutorPolicy::kWhitelistWarning) {
+ if (policy == XmlActionExecutorPolicy::kAllowListWarning) {
// Treat the error only as a warning.
diag->Warn(error_msg);
} else {
- // Policy is XmlActionExecutorPolicy::kWhitelist, we should fail.
+ // Policy is XmlActionExecutorPolicy::kAllowList, we should fail.
diag->Error(error_msg);
error = true;
}
@@ -94,7 +94,7 @@
Element* el = doc->root.get();
if (!el) {
- if (policy == XmlActionExecutorPolicy::kWhitelist) {
+ if (policy == XmlActionExecutorPolicy::kAllowList) {
source_diag.Error(DiagMessage() << "no root XML tag found");
return false;
}
@@ -109,7 +109,7 @@
return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
}
- if (policy == XmlActionExecutorPolicy::kWhitelist) {
+ if (policy == XmlActionExecutorPolicy::kAllowList) {
DiagMessage error_msg(el->line_number);
error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index f689b2a..a0ad1da 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -37,12 +37,12 @@
// The actions defined must match and run. If an element is found that does not match an action,
// an error occurs.
// Note: namespaced elements are always ignored.
- kWhitelist,
+ kAllowList,
// The actions defined should match and run. if an element is found that does not match an
// action, a warning is printed.
// Note: namespaced elements are always ignored.
- kWhitelistWarning,
+ kAllowListWarning,
};
// Contains the actions to perform at this XML node. This is a recursive data structure that
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index d39854e..d47b495 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -60,10 +60,10 @@
StdErrDiagnostics diag;
doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>");
- ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+ ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kAllowList, &diag, doc.get()));
doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>");
- ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+ ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kAllowList, &diag, doc.get()));
}
} // namespace xml
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index f25fcdc..99aaa3c 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -11,7 +11,7 @@
if (( count == 0 )); then
echo
fi
- echo -e "\033[0;31mThe source of truth for '$file' is in AOSP.\033[0m"
+ echo -e "\033[0;31;47mThe source of truth for '$file' is in AOSP.\033[0m"
(( count++ ))
done < <(git show --name-only --pretty=format: $1 | grep -- "$2")
if (( count != 0 )); then
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index de6b478..8a282e5 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -13,9 +13,7 @@
# 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.
-"""
-Generate API lists for non-SDK API enforcement.
-"""
+"""Generate API lists for non-SDK API enforcement."""
import argparse
from collections import defaultdict
import functools
@@ -24,27 +22,47 @@
import sys
# Names of flags recognized by the `hiddenapi` tool.
-FLAG_WHITELIST = "whitelist"
-FLAG_GREYLIST = "greylist"
-FLAG_BLACKLIST = "blacklist"
-FLAG_GREYLIST_MAX_O = "greylist-max-o"
-FLAG_GREYLIST_MAX_P = "greylist-max-p"
-FLAG_GREYLIST_MAX_Q = "greylist-max-q"
-FLAG_GREYLIST_MAX_R = "greylist-max-r"
-FLAG_CORE_PLATFORM_API = "core-platform-api"
-FLAG_PUBLIC_API = "public-api"
-FLAG_SYSTEM_API = "system-api"
-FLAG_TEST_API = "test-api"
+FLAG_SDK = 'sdk'
+FLAG_UNSUPPORTED = 'unsupported'
+FLAG_BLOCKED = 'blocked'
+FLAG_MAX_TARGET_O = 'max-target-o'
+FLAG_MAX_TARGET_P = 'max-target-p'
+FLAG_MAX_TARGET_Q = 'max-target-q'
+FLAG_MAX_TARGET_R = 'max-target-r'
+FLAG_CORE_PLATFORM_API = 'core-platform-api'
+FLAG_PUBLIC_API = 'public-api'
+FLAG_SYSTEM_API = 'system-api'
+FLAG_TEST_API = 'test-api'
+
+OLD_FLAG_SDK = "whitelist"
+OLD_FLAG_UNSUPPORTED = "greylist"
+OLD_FLAG_BLOCKED = "blacklist"
+OLD_FLAG_MAX_TARGET_O = "greylist-max-o"
+OLD_FLAG_MAX_TARGET_P = "greylist-max-p"
+OLD_FLAG_MAX_TARGET_Q = "greylist-max-q"
+OLD_FLAG_MAX_TARGET_R = "greylist-max-r"
+
+OLD_FLAGS_TO_NEW = {
+ OLD_FLAG_SDK: FLAG_SDK,
+ OLD_FLAG_UNSUPPORTED: FLAG_UNSUPPORTED,
+ OLD_FLAG_BLOCKED: FLAG_BLOCKED,
+ OLD_FLAG_MAX_TARGET_O: FLAG_MAX_TARGET_O,
+ OLD_FLAG_MAX_TARGET_P: FLAG_MAX_TARGET_P,
+ OLD_FLAG_MAX_TARGET_Q: FLAG_MAX_TARGET_Q,
+ OLD_FLAG_MAX_TARGET_R: FLAG_MAX_TARGET_R,
+}
+
+NEW_FLAGS_TO_OLD = dict(zip(OLD_FLAGS_TO_NEW.values(), OLD_FLAGS_TO_NEW.keys()))
# List of all known flags.
FLAGS_API_LIST = [
- FLAG_WHITELIST,
- FLAG_GREYLIST,
- FLAG_BLACKLIST,
- FLAG_GREYLIST_MAX_O,
- FLAG_GREYLIST_MAX_P,
- FLAG_GREYLIST_MAX_Q,
- FLAG_GREYLIST_MAX_R,
+ FLAG_SDK,
+ FLAG_UNSUPPORTED,
+ FLAG_BLOCKED,
+ FLAG_MAX_TARGET_O,
+ FLAG_MAX_TARGET_P,
+ FLAG_MAX_TARGET_Q,
+ FLAG_MAX_TARGET_R,
]
ALL_FLAGS = FLAGS_API_LIST + [
FLAG_CORE_PLATFORM_API,
@@ -58,7 +76,7 @@
# Suffix used in command line args to express that only known and
# otherwise unassigned entries should be assign the given flag.
-# For example, the P dark greylist is checked in as it was in P,
+# For example, the max-target-P list is checked in as it was in P,
# but signatures have changes since then. The flag instructs this
# script to skip any entries which do not exist any more.
FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
@@ -87,6 +105,7 @@
HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
+
def get_args():
"""Parses command line arguments.
@@ -113,6 +132,7 @@
return parser.parse_args()
+
def read_lines(filename):
"""Reads entire file and return it as a list of lines.
@@ -130,8 +150,9 @@
lines = map(lambda line: line.strip(), lines)
return set(lines)
+
def write_lines(filename, lines):
- """Writes list of lines into a file, overwriting the file it it exists.
+ """Writes list of lines into a file, overwriting the file if it exists.
Args:
filename (string): Path to the file to be writting into.
@@ -141,6 +162,7 @@
with open(filename, 'w') as f:
f.writelines(lines)
+
def extract_package(signature):
"""Extracts the package from a signature.
@@ -159,6 +181,7 @@
package_name = full_class_name.rpartition("/")[0]
return package_name.replace('/', '.')
+
class FlagsDict:
def __init__(self):
self._dict_keyset = set()
@@ -182,6 +205,36 @@
"Please visit go/hiddenapi for more information.").format(
source, "\n".join(flags_subset - ALL_FLAGS_SET))
+ def convert_to_new_flag(self, flag):
+ """Converts old flag to a new variant.
+
+ Flags that are considered old are replaced with new versions.
+ Otherwise, it is a no-op.
+
+ Args:
+ flag: a string, representing SDK flag.
+
+ Returns:
+ A string. Result of conversion.
+
+ """
+ return OLD_FLAGS_TO_NEW.get(flag, flag)
+
+ def convert_to_old_flag(self, flag):
+ """Converts a new flag to a old variant.
+
+ No-op if there is no suitable old flag.
+ Only used to support backwards compatibility.
+
+ Args:
+ flag: a string, representing SDK flag.
+
+ Returns:
+ A string. Result of conversion.
+
+ """
+ return NEW_FLAGS_TO_OLD.get(flag, flag)
+
def filter_apis(self, filter_fn):
"""Returns APIs which match a given predicate.
@@ -212,10 +265,16 @@
def generate_csv(self):
"""Constructs CSV entries from a dictionary.
+ Old versions of flags are used to generate the file.
+
Returns:
List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
"""
- return sorted(map(lambda api: ",".join([api] + sorted(self._dict[api])), self._dict))
+ lines = []
+ for api in self._dict:
+ flags = sorted([self.convert_to_old_flag(flag) for flag in self._dict[api]])
+ lines.append(",".join([api] + flags))
+ return sorted(lines)
def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
"""Parses CSV entries and merges them into a given dictionary.
@@ -237,17 +296,16 @@
self._dict_keyset.update([ csv[0] for csv in csv_values ])
# Check that all flags are known.
- csv_flags = set(functools.reduce(
- lambda x, y: set(x).union(y),
- [ csv[1:] for csv in csv_values ],
- []))
+ csv_flags = set()
+ for csv in csv_values:
+ csv_flags.update([self.convert_to_new_flag(flag) for flag in csv[1:]])
self._check_flags_set(csv_flags, source)
# Iterate over all CSV lines, find entry in dict and append flags to it.
for csv in csv_values:
- flags = csv[1:]
+ flags = [self.convert_to_new_flag(flag) for flag in csv[1:]]
if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
- flags.append(FLAG_WHITELIST)
+ flags.append(FLAG_SDK)
self._dict[csv[0]].update(flags)
def assign_flag(self, flag, apis, source="<unknown>"):
@@ -271,6 +329,7 @@
for api in apis:
self._dict[api].add(flag)
+
def main(argv):
# Parse arguments.
args = vars(get_args())
@@ -287,8 +346,8 @@
flags.parse_and_merge_csv(read_lines(filename), filename)
# Combine inputs which do not require any particular order.
- # (1) Assign serialization API to whitelist.
- flags.assign_flag(FLAG_WHITELIST, flags.filter_apis(IS_SERIALIZATION))
+ # (1) Assign serialization API to SDK.
+ flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
# (2) Merge text files with a known flag into the dictionary.
for flag in ALL_FLAGS:
@@ -314,8 +373,8 @@
valid_entries = flags.filter_apis(should_add_signature_to_list)
flags.assign_flag(flag, valid_entries)
- # Assign all remaining entries to the blacklist.
- flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+ # Mark all remaining entries as blocked.
+ flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
# Write output.
write_lines(args["output"], flags.generate_csv())
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 55c3a7d..321c400 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -23,7 +23,7 @@
# Initialize flags so that A and B are put on the whitelist and
# C, D, E are left unassigned. Try filtering for the unassigned ones.
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
'C', 'D', 'E'])
filter_set = flags.filter_apis(lambda api, flags: not flags)
self.assertTrue(isinstance(filter_set, set))
@@ -32,10 +32,10 @@
def test_get_valid_subset_of_unassigned_keys(self):
# Create flags where only A is unassigned.
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
- flags.assign_flag(FLAG_GREYLIST, set(['C']))
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
+ flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
+ [ 'A,' + OLD_FLAG_SDK, 'B', 'C,' + OLD_FLAG_UNSUPPORTED ])
# Check three things:
# (1) B is selected as valid unassigned
@@ -50,20 +50,21 @@
# Test empty CSV entry.
self.assertEqual(flags.generate_csv(), [])
- # Test new additions.
+ # Test new additions. CSV generator produces values with old flags
+ # to be backwards compatible.
flags.parse_and_merge_csv([
- 'A,' + FLAG_GREYLIST,
- 'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O,
- 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
- 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+ 'A,' + FLAG_UNSUPPORTED,
+ 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+ 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+ 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
])
self.assertEqual(flags.generate_csv(), [
- 'A,' + FLAG_GREYLIST,
- 'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O,
- 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
- 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+ 'A,' + OLD_FLAG_UNSUPPORTED,
+ 'B,' + OLD_FLAG_BLOCKED + "," + OLD_FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SYSTEM_API + ',' + OLD_FLAG_SDK,
+ 'D,' + OLD_FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+ 'E,' + OLD_FLAG_BLOCKED + ',' + FLAG_TEST_API,
])
# Test unknown flag.
@@ -72,16 +73,16 @@
def test_assign_flag(self):
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
# Test new additions.
- flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
+ flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
+ [ 'A,' + OLD_FLAG_UNSUPPORTED + "," + OLD_FLAG_SDK, 'B,' + OLD_FLAG_UNSUPPORTED ])
# Test invalid API signature.
with self.assertRaises(AssertionError):
- flags.assign_flag(FLAG_WHITELIST, set([ 'C' ]))
+ flags.assign_flag(FLAG_SDK, set([ 'C' ]))
# Test invalid flag.
with self.assertRaises(AssertionError):
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index e3b6db0..43387fc 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -121,10 +121,26 @@
],
target: {
android: {
- shared_libs: ["libstatssocket"],
+ shared_libs: [
+ "libstatssocket",
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
host: {
- static_libs: ["libstatssocket"],
+ static_libs: [
+ "libstatssocket",
+ "libstatspull",
+ "statsd-aidl-ndk_platform",
+ ],
+ shared_libs: ["libbinder_ndk"],
+ export_static_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
},
}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 4c741c4..fe6ca55 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -72,7 +72,7 @@
SourceLocation loc;
if (field->GetSourceLocation(&loc)) {
- // TODO: this will work if we can figure out how to pass
+ // TODO(b/162454173): this will work if we can figure out how to pass
// --include_source_info to protoc
fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
} else {
@@ -111,7 +111,6 @@
case FieldDescriptor::TYPE_GROUP:
return JAVA_TYPE_UNKNOWN;
case FieldDescriptor::TYPE_MESSAGE:
- // TODO: not the final package name
if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
return JAVA_TYPE_ATTRIBUTION_CHAIN;
} else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
@@ -147,7 +146,7 @@
void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
for (int i = 0; i < enumDescriptor.value_count(); i++) {
atomField->enumValues[enumDescriptor.value(i)->number()] =
- enumDescriptor.value(i)->name().c_str();
+ enumDescriptor.value(i)->name();
}
}
@@ -528,7 +527,7 @@
vector<java_type_t> signature;
errorCount += collate_atom(atom, atomDecl.get(), &signature);
- if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) {
+ if (!atomDecl->primaryFields.empty() && atomDecl->exclusiveField == 0) {
print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
atomField->name().c_str());
errorCount++;
@@ -541,8 +540,7 @@
atomField->name().c_str());
errorCount++;
continue;
- }
- else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
+ } else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
(oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
atomField->name().c_str());
@@ -578,7 +576,7 @@
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
jt++) {
- printf(" %d", (int)*jt);
+ printf(" %d", static_cast<int>(*jt));
}
printf("\n");
}
@@ -589,7 +587,7 @@
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
jt++) {
- printf(" %d", (int)*jt);
+ printf(" %d", static_cast<int>(*jt));
}
printf("\n");
}
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index e637ed9..5d196c4 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -47,8 +47,8 @@
*
* `OneofDescriptor::name()` returns the name of the oneof.
*/
-const string ONEOF_PUSHED_ATOM_NAME = "pushed";
-const string ONEOF_PULLED_ATOM_NAME = "pulled";
+const char ONEOF_PUSHED_ATOM_NAME[] = "pushed";
+const char ONEOF_PULLED_ATOM_NAME[] = "pulled";
enum AnnotationId : uint8_t {
ANNOTATION_ID_IS_UID = 1,
@@ -63,7 +63,7 @@
const int ATOM_ID_FIELD_NUMBER = -1;
-const string DEFAULT_MODULE_NAME = "DEFAULT";
+const char DEFAULT_MODULE_NAME[] = "DEFAULT";
/**
* The types for atom parameters.
@@ -95,9 +95,9 @@
int intValue;
bool boolValue;
- AnnotationValue(const int value) : intValue(value) {
+ explicit AnnotationValue(const int value) : intValue(value) {
}
- AnnotationValue(const bool value) : boolValue(value) {
+ explicit AnnotationValue(const bool value) : boolValue(value) {
}
};
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index ffbe9f8..6fcf267 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -42,6 +42,7 @@
static void write_java_annotation_constants(FILE* out) {
fprintf(out, " // Annotation constants.\n");
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id);
}
@@ -56,6 +57,7 @@
return;
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
const string atomConstant = make_constant_name(atomDecl->name);
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
@@ -102,7 +104,7 @@
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
chainField.name.c_str());
}
@@ -243,13 +245,15 @@
return 0;
}
-static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pushed_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write(int code");
- write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ const vector<java_type_t>& signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ write_method_signature(out, signature, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
@@ -259,7 +263,7 @@
indent = " ";
}
- int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
attributionDecl, indent);
if (ret != 0) {
return ret;
@@ -274,8 +278,8 @@
fprintf(out, " } else {\n");
fprintf(out, " QLogger.write(code");
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signatureInfoMapIt->first.begin();
- arg != signatureInfoMapIt->first.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -299,18 +303,20 @@
return 0;
}
-static int write_java_build_stats_event_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pulled_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static StatsEvent buildStatsEvent(int code");
- write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ const vector<java_type_t>& signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ write_method_signature(out, signature, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
string indent("");
- int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
attributionDecl, indent);
if (ret != 0) {
return ret;
@@ -357,9 +363,9 @@
// Print write methods.
fprintf(out, " // Write methods\n");
- errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ errors += write_java_pushed_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
- errors += write_java_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ errors += write_java_pulled_methods(out, atoms.pulledAtomsSignatureInfoMap,
attributionDecl);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 8b3b505..afd992b 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
#include <stdio.h>
#include <string.h>
@@ -28,11 +29,11 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaPackage, const bool supportQ,
const bool supportWorkSource);
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index d21e270..be7cb4a 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -65,7 +65,7 @@
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
chainField.name.c_str());
}
@@ -407,7 +407,7 @@
if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
indent.c_str());
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
}
fprintf(out, ") {\n");
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index c511a84..622ef3e 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
#include <stdio.h>
#include <string.h>
@@ -28,8 +29,6 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
void write_java_q_logging_constants(FILE* out, const string& indent);
int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
@@ -44,3 +43,5 @@
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index b888ce9..d210184 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -16,7 +16,6 @@
#include "utils.h"
using namespace google::protobuf;
-using namespace std;
namespace android {
namespace stats_log_api_gen {
@@ -145,7 +144,7 @@
index++;
}
- if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) {
+ if (cppFilename.empty() && headerFilename.empty() && javaFilename.empty()) {
print_usage();
return 1;
}
@@ -175,9 +174,9 @@
&attributionSignature);
// Write the .cpp file
- if (cppFilename.size() != 0) {
+ if (!cppFilename.empty()) {
FILE* out = fopen(cppFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
return 1;
}
@@ -198,9 +197,9 @@
}
// Write the .h file
- if (headerFilename.size() != 0) {
+ if (!headerFilename.empty()) {
FILE* out = fopen(headerFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
return 1;
}
@@ -214,24 +213,24 @@
}
// Write the .java file
- if (javaFilename.size() != 0) {
- if (javaClass.size() == 0) {
+ if (!javaFilename.empty()) {
+ if (javaClass.empty()) {
fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
return 1;
}
- if (javaPackage.size() == 0) {
+ if (javaPackage.empty()) {
fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
return 1;
}
- if (moduleName.size() == 0) {
+ if (moduleName.empty()) {
fprintf(stderr, "Must supply --module if supplying a Java filename");
return 1;
}
FILE* out = fopen(javaFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
return 1;
}
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 0c6c009..b4fb8dd 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -24,6 +24,7 @@
static void write_native_annotation_constants(FILE* out) {
fprintf(out, "// Annotation constants.\n");
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
}
@@ -39,6 +40,7 @@
return;
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
const string atomConstant = make_constant_name(atomDecl->name);
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
@@ -60,8 +62,6 @@
}
break;
case ANNOTATION_TYPE_BOOL:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
methodSuffix.c_str(), annotationConstant.c_str(),
annotation->value.boolValue ? "true" : "false");
@@ -82,21 +82,78 @@
}
}
-static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
+static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
+ const AtomDecl& attributionDecl) {
+ int argIndex = 1;
+ fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ fprintf(out,
+ " AStatsEvent_writeAttributionChain(event, "
+ "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
+ "static_cast<uint8_t>(%s_length));\n",
+ uidName, tagName, uidName);
+ break;
+ }
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ " AStatsEvent_writeByteArray(event, "
+ "reinterpret_cast<const uint8_t*>(arg%d.arg), "
+ "arg%d.arg_length);\n",
+ argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ argIndex++;
+ }
+ return 0;
+}
+
+static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
fprintf(out, "\n");
- for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
+ write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
- int argIndex = 1;
+ // Write method body.
if (supportQ) {
+ int argIndex = 1;
fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\n");
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
@@ -138,78 +195,37 @@
write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "");
argIndex++;
}
- fprintf(out, " return event.writeToSocket();\n");
+ fprintf(out, " return event.writeToSocket();\n"); // end method body.
} else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
- fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out,
- " AStatsEvent_writeAttributionChain(event, "
- "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
- "static_cast<uint8_t>(%s_length));\n",
- uidName, tagName, uidName);
- break;
- }
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- " AStatsEvent_writeByteArray(event, "
- "reinterpret_cast<const uint8_t*>(arg%d.arg), "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- break;
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_INT: // Fall through.
- case JAVA_TYPE_ENUM:
- fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- argIndex++;
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
}
fprintf(out, " const int ret = AStatsEvent_write(event);\n");
fprintf(out, " AStatsEvent_release(event);\n");
- fprintf(out, " return ret;\n");
+ fprintf(out, " return ret;\n"); // end method body.
}
- fprintf(out, "}\n\n");
+ fprintf(out, "}\n\n"); // end method.
}
return 0;
}
-static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
+static void write_native_stats_write_non_chained_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
fprintf(out, "\n");
- for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
- signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
+ for (auto signature_it = signatureInfoMap.begin();
+ signature_it != signatureInfoMap.end(); signature_it++) {
vector<java_type_t> signature = signature_it->first;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write_non_chained", signature,
+ write_native_method_signature(out, "int stats_write_non_chained(", signature,
attributionDecl, " {");
vector<java_type_t> newSignature;
@@ -235,6 +251,35 @@
}
}
+static int write_native_build_stats_event_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
+ fprintf(out, "\n");
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ vector<java_type_t> signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ // Key value pairs not supported in native.
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
+ continue;
+ }
+ write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ signature, attributionDecl, " {");
+
+ fprintf(out, " AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
+ }
+ fprintf(out, " AStatsEvent_build(event);\n"); // end method body.
+
+ fprintf(out, "}\n\n"); // end method.
+ }
+ return 0;
+}
+
static void write_native_method_header(FILE* out, const string& methodName,
const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
@@ -243,7 +288,8 @@
vector<java_type_t> signature = signatureInfoMapIt->first;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
write_native_method_signature(out, methodName, signature, attributionDecl, ";");
@@ -262,13 +308,22 @@
fprintf(out, "#include <StatsEventCompat.h>\n");
} else {
fprintf(out, "#include <stats_event.h>\n");
+
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
}
+
+
fprintf(out, "\n");
write_namespace(out, cppNamespace);
- write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
- write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
+ write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ attributionDecl);
// Print footer
fprintf(out, "\n");
@@ -288,6 +343,9 @@
fprintf(out, "#include <vector>\n");
fprintf(out, "#include <map>\n");
fprintf(out, "#include <set>\n");
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
fprintf(out, "\n");
write_namespace(out, cppNamespace);
@@ -337,12 +395,22 @@
fprintf(out, "//\n");
fprintf(out, "// Write methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
+ write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
+ fprintf(out, "\n");
fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
+ write_native_method_header(out, "int stats_write_non_chained(", atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ fprintf(out, "\n");
+
+ // Print pulled atoms methods.
+ fprintf(out, "//\n");
+ fprintf(out, "// Add AStatsEvent methods\n");
+ fprintf(out, "//\n");
+ write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ atoms.pulledAtomsSignatureInfoMap,
attributionDecl);
fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
index 264d4db..4e42d1f 100644
--- a/tools/stats_log_api_gen/native_writer.h
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
#include <stdio.h>
#include <string.h>
@@ -24,8 +25,6 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace, const string& importHeader,
const bool supportQ);
@@ -35,3 +34,5 @@
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 5fd728a..6f78921 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -24,7 +24,6 @@
namespace stats_log_api_gen {
using std::map;
-using std::set;
using std::vector;
/**
@@ -32,11 +31,11 @@
*/
static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) {
va_list args;
- vector<java_type_t> v;
+ vector<java_type_t> v(count);
va_start(args, count);
for (int i = 0; i < count; i++) {
- v.push_back((java_type_t)va_arg(args, int));
+ v[i] = static_cast<java_type_t>(va_arg(args, int));
}
va_end(args);
@@ -222,7 +221,7 @@
Atoms atoms;
int errorCount =
collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_TRUE(errorCount > 0);
+ EXPECT_GT(errorCount, 0);
}
TEST(CollationTest, PassOnLogFromModuleAtom) {
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index abb8913..1eaf42a 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -16,11 +16,30 @@
#include "utils.h"
-#include "android-base/strings.h"
-
namespace android {
namespace stats_log_api_gen {
+/**
+ * Inlining this method because "android-base/strings.h" is not available on
+ * google3.
+ */
+static vector<string> Split(const string& s, const string& delimiters) {
+ GOOGLE_CHECK_NE(delimiters.size(), 0U);
+
+ vector<string> result;
+
+ size_t base = 0;
+ size_t found;
+ while (true) {
+ found = s.find_first_of(delimiters, base);
+ result.push_back(s.substr(base, found - base));
+ if (found == s.npos) break;
+ base = found + 1;
+ }
+
+ return result;
+}
+
static void build_non_chained_decl_map(const Atoms& atoms,
std::map<int, AtomDeclSet::const_iterator>* decl_map) {
for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
@@ -29,6 +48,20 @@
}
}
+const map<AnnotationId, string>& get_annotation_id_constants() {
+ static const map<AnnotationId, string>* ANNOTATION_ID_CONSTANTS =
+ new map<AnnotationId, string>{
+ {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
+ {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
+ {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
+ {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
+ {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
+ {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
+ {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+
+ return *ANNOTATION_ID_CONSTANTS;
+}
+
/**
* Turn lower and camel case into upper case with underscores.
*/
@@ -102,15 +135,15 @@
// Writes namespaces for the cpp and header files, returning the number of
// namespaces written.
void write_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
- for (string cppNamespace : cppNamespaceVec) {
+ vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
+ for (const string& cppNamespace : cppNamespaceVec) {
fprintf(out, "namespace %s {\n", cppNamespace.c_str());
}
}
// Writes namespace closing brackets for cpp and header files.
void write_closing_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+ vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
fprintf(out, "} // namespace %s\n", it->c_str());
}
@@ -123,7 +156,7 @@
for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
chainField.name.c_str());
@@ -182,15 +215,15 @@
fprintf(out, "\n");
}
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer) {
- fprintf(out, "%s(int32_t code", methodName.c_str());
+ fprintf(out, "%sint32_t code", signaturePrefix.c_str());
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
chainField.name.c_str());
@@ -222,7 +255,7 @@
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", %s", chainField.name.c_str());
} else {
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index 73e0cb8..13a7e2d 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_UTILS_H
+#define ANDROID_STATS_LOG_API_GEN_UTILS_H
#include <stdio.h>
#include <string.h>
@@ -28,23 +29,14 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
-const string DEFAULT_CPP_NAMESPACE = "android,util";
-const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const char DEFAULT_CPP_NAMESPACE[] = "android,util";
+const char DEFAULT_CPP_HEADER_IMPORT[] = "statslog.h";
const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
-const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = {
- {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
- {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
- {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
- {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
- {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
- {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
- {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+const map<AnnotationId, string>& get_annotation_id_constants();
string make_constant_name(const string& str);
@@ -59,7 +51,7 @@
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer);
@@ -81,3 +73,5 @@
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_UTILS_H
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 4d3a2c0..68eb1bb 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -943,6 +943,9 @@
*/
@Nullable
public WifiEnterpriseConfig getEnterpriseConfig() {
+ if (!wifiConfiguration.isEnterprise()) {
+ return null;
+ }
return wifiConfiguration.enterpriseConfig;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 16b4ad0..f0839e9 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -62,6 +62,7 @@
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -92,6 +93,7 @@
assertEquals(0, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -122,6 +124,7 @@
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -152,6 +155,7 @@
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -174,6 +178,7 @@
assertTrue(suggestion.wifiConfiguration.requirePmf);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -197,6 +202,7 @@
assertTrue(suggestion.wifiConfiguration.requirePmf);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
@@ -230,6 +236,7 @@
// here.
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -286,6 +293,7 @@
.get(WifiConfiguration.GroupCipher.SMS4));
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
suggestion.wifiConfiguration.preSharedKey);
+ assertNull(suggestion.getEnterpriseConfig());
}
@@ -316,6 +324,7 @@
suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
assertEquals(TEST_WAPI_CERT_SUITE,
suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -345,6 +354,7 @@
suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
assertEquals("",
suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -367,6 +377,7 @@
assertEquals(suggestion.getPasspointConfig().getMeteredOverride(),
WifiConfiguration.METERED_OVERRIDE_METERED);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 971aa8e..79e95e8 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -267,42 +267,42 @@
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1L0() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 0, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 0, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeTm3L2() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(-3, 2, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(-3, 2, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1Lm2() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, -2, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, -2, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1L3() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 3, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 3, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT3L1() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(3, 1, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(3, 1, testTlv);
}
/**
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index f2961db..b65de6b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -45,7 +45,7 @@
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
@@ -78,7 +78,7 @@
@Test
public void testEmptyDoesntMatchAnything() {
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier();
- WifiAwareNetworkSpecifier ns = getDummyNetworkSpecifier(6);
+ WifiAwareNetworkSpecifier ns = getMockNetworkSpecifier(6);
collector.checkThat("No match expected", ns.canBeSatisfiedBy(dut), equalTo(false));
}
@@ -88,9 +88,9 @@
*/
@Test
public void testSingleMatch() {
- WifiAwareNetworkSpecifier nsThis = getDummyNetworkSpecifier(6);
+ WifiAwareNetworkSpecifier nsThis = getMockNetworkSpecifier(6);
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(nsThis);
- WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(8);
+ WifiAwareNetworkSpecifier nsOther = getMockNetworkSpecifier(8);
collector.checkThat("Match expected", nsThis.canBeSatisfiedBy(dut), equalTo(true));
collector.checkThat("No match expected", nsOther.canBeSatisfiedBy(dut), equalTo(false));
}
@@ -105,12 +105,12 @@
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
- WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(10000);
+ WifiAwareNetworkSpecifier nsOther = getMockNetworkSpecifier(10000);
for (WifiAwareNetworkSpecifier nsThis: nsSet) {
collector.checkThat("Match expected", nsThis.canBeSatisfiedBy(dut), equalTo(true));
@@ -127,13 +127,13 @@
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
- nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ nsSet.add(getMockNetworkSpecifier(100 + numNs));
WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
@@ -149,13 +149,13 @@
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
- nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ nsSet.add(getMockNetworkSpecifier(100 + numNs));
WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
@@ -165,10 +165,10 @@
// utilities
/**
- * Returns a WifiAwareNetworkSpecifier with dummy (but valid) entries. Each can be
+ * Returns a WifiAwareNetworkSpecifier with mock (but valid) entries. Each can be
* differentiated (made unique) by specifying a different client ID.
*/
- WifiAwareNetworkSpecifier getDummyNetworkSpecifier(int clientId) {
+ WifiAwareNetworkSpecifier getMockNetworkSpecifier(int clientId) {
return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
null, null, 10, 5);
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index c5f9804..43d728b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1585,7 +1585,7 @@
public void testWifiAwareNetworkCapabilitiesParcel() throws UnknownHostException {
final Inet6Address inet6 = MacAddress.fromString(
"11:22:33:44:55:66").getLinkLocalIpv6FromEui48Mac();
- // note: dummy scope = 5
+ // note: placeholder scope = 5
final Inet6Address inet6Scoped = Inet6Address.getByAddress(null, inet6.getAddress(), 5);
final int port = 5;
final int transportProtocol = 6;